Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ package.json → semantic-release config (do not modify)
# Build
docker build -t powerpipe:test .

# Build for a specific version
docker build --build-arg POWERPIPE_VERSION=1.5.1 -t powerpipe:test .

# Smoke test
docker run --rm powerpipe:test powerpipe --version

Expand All @@ -60,6 +63,73 @@ curl -sf http://localhost:9033/ && echo "OK"
docker stop pp-test
```

### Unit tests (no Docker required)

```bash
pip install -r tests/requirements.txt

# Full suite with coverage
python3 -m pytest tests/ --cov=compare_snapshots --cov-report=term-missing

# Single test
python3 -m pytest tests/test_compare_snapshots.py::TestDiffLists::test_added_items -v
```

### Lint the Dockerfile

```bash
docker run --rm -i hadolint/hadolint < Dockerfile
```

### Container structure tests (requires built image)

```bash
docker run --rm \
-v "$PWD/structure-tests.yaml:/structure-tests.yaml:ro" \
-v /var/run/docker.sock:/var/run/docker.sock \
gcr.io/gcp-runtimes/container-structure-test:latest \
test --image powerpipe:test --config /structure-tests.yaml
```

### Security scan

```bash
docker run --rm \
-v /var/run/docker.sock:/var/run/docker.sock \
aquasec/trivy image --severity CRITICAL --ignore-unfixed powerpipe:test
```

## Commit Message Format

This repo uses [Conventional Commits](https://www.conventionalcommits.org/):

```
feat: add support for multi-arch builds
fix: correct workspace directory permissions
chore: bump powerpipe to 1.6.0
docs: add mod installation example
```

| Type | When to use |
|------|------------|
| `feat` | New feature or capability |
| `fix` | Bug fix |
| `chore` | Maintenance (version bumps, CI tweaks) |
| `docs` | Documentation only |
| `refactor` | Code restructure without behaviour change |

## Key Conventions

- **Port 9033** is Powerpipe's HTTP port. Port 9193 belongs to Steampipe — don't confuse them.
- **UID 9193 / GID 0** — deliberate for OpenShift restricted SCC compatibility, consistent with the Steampipe image.
- **`git` is a required runtime dep** — `powerpipe mod install` fetches mods from GitHub repos at runtime.
- **Mods, not plugins** — Powerpipe uses *mods* (`powerpipe mod install`). "Plugins" is Steampipe terminology.
- **`POWERPIPE_DATABASE` is deprecated** — the preferred approach is connection config files, not this env var.
- **`ARG TARGETARCH`** is populated automatically by Docker Buildx for multi-arch builds (`linux/amd64`, `linux/arm64`). Do not hardcode it.
- **Unit tests import from `scripts/`** — `tests/conftest.py` prepends `scripts/` to `sys.path`, enabling `import compare_snapshots` without an installable package.
- **`behavior-check` CI job only runs on PRs when `POWERPIPE_VERSION` changes** in the Dockerfile. It extracts a fresh CLI snapshot, diffs it against `cli-snapshot.json`, and posts the result as a PR comment mentioning `@copilot`.
- **`structure-tests.yaml`** validates all ENV vars set in the Dockerfile plus binary presence, metadata labels, exposed port, and default CMD. When adding/removing `ENV` lines in the Dockerfile, update this file too.

## Documentation Format

Flag tables use this format:
Expand Down
21 changes: 21 additions & 0 deletions context7.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"$schema": "https://context7.com/schema/context7.json",
"url": "https://context7.com/devops-ia/powerpipe",
"projectTitle": "Powerpipe Docker Image",
"description": "Community Docker image for Powerpipe — dashboards and compliance benchmarks for DevOps. Visualize cloud configurations and assess security posture against CIS, NIST, SOC 2, and other compliance frameworks. Multi-arch (amd64/arm64), production-ready.",
"folders": ["docs", "examples"],
"excludeFolders": ["scripts", ".github", "tests", "openspec"],
"excludeFiles": ["CONTRIBUTING.md", "structure-tests.yaml", "trivy.yaml", "cli-snapshot.json"],
"rules": [
"Always set POWERPIPE_DATABASE to a valid Steampipe connection string (postgresql://steampipe:<password>@<host>:9193/steampipe) — Powerpipe cannot start without it",
"Always use --listen network flag (or POWERPIPE_LISTEN=network) to accept connections from outside the container",
"Powerpipe serves dashboards on port 9033 (not 9193 — that is Steampipe's PostgreSQL port)",
"The container runs as UID 9193 (GID 0) — ensure mounted volumes have correct ownership with chown -R 9193:0",
"Mount the mod workspace as a named volume at /workspace to persist installed mods across container restarts",
"Use depends_on with healthcheck condition when composing Steampipe + Powerpipe to ensure Steampipe is ready before Powerpipe starts",
"Install mods with docker exec powerpipe powerpipe mod install <mod-url> after the container is running",
"Use POWERPIPE_BASE_URL when running behind a reverse proxy or when sharing dashboard links externally",
"Prefer ghcr.io/devops-ia/powerpipe over devopsiaci/powerpipe (Docker Hub mirror) for GitHub Actions workflows",
"Run one-shot benchmarks without starting the server: powerpipe benchmark run <benchmark> --output brief"
]
}
213 changes: 213 additions & 0 deletions docs/integrations.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
# Integrations

Powerpipe serves an HTTP dashboard on port 9033. It works with any tool that can embed or proxy HTTP.

## Steampipe + Powerpipe (Docker Compose)

The standard full-stack setup pairs Powerpipe with Steampipe as the data source:

```yaml
# docker-compose.yml
services:
steampipe:
image: ghcr.io/devops-ia/steampipe:2.4.1
container_name: steampipe
command: ["steampipe", "service", "start", "--foreground", "--database-listen", "network"]
ports:
- "9193:9193"
environment:
STEAMPIPE_DATABASE_PASSWORD: steampipe
volumes:
- steampipe-data:/home/steampipe/.steampipe
- ./aws.spc:/home/steampipe/.steampipe/config/aws.spc:ro
healthcheck:
test: ["CMD", "pg_isready", "-h", "localhost", "-p", "9193", "-U", "steampipe"]
interval: 10s
timeout: 5s
retries: 10
start_period: 30s

powerpipe:
image: ghcr.io/devops-ia/powerpipe:1.5.1
container_name: powerpipe
command: ["powerpipe", "server", "--listen", "network"]
ports:
- "9033:9033"
environment:
POWERPIPE_DATABASE: "postgresql://steampipe:steampipe@steampipe:9193/steampipe"
volumes:
- powerpipe-workspace:/workspace
depends_on:
steampipe:
condition: service_healthy

volumes:
steampipe-data:
powerpipe-workspace:
```

```bash
docker compose up -d
open http://localhost:9033
```

## Reverse proxy (nginx)

Expose Powerpipe dashboards under a custom path or domain:

```nginx
# nginx.conf
server {
listen 80;
server_name dashboards.example.com;

location / {
proxy_pass http://powerpipe:9033;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
```

Set `POWERPIPE_BASE_URL` so that share links use the public URL:

```yaml
services:
powerpipe:
image: ghcr.io/devops-ia/powerpipe:1.5.1
environment:
POWERPIPE_DATABASE: "postgresql://steampipe:steampipe@steampipe:9193/steampipe"
POWERPIPE_BASE_URL: "https://dashboards.example.com"
```

Full compose with nginx:

```yaml
# docker-compose-nginx.yml
services:
steampipe:
image: ghcr.io/devops-ia/steampipe:2.4.1
command: ["steampipe", "service", "start", "--foreground", "--database-listen", "network"]
environment:
STEAMPIPE_DATABASE_PASSWORD: steampipe
volumes:
- steampipe-data:/home/steampipe/.steampipe
healthcheck:
test: ["CMD", "pg_isready", "-h", "localhost", "-p", "9193", "-U", "steampipe"]
interval: 10s
timeout: 5s
retries: 10
start_period: 30s

powerpipe:
image: ghcr.io/devops-ia/powerpipe:1.5.1
environment:
POWERPIPE_DATABASE: "postgresql://steampipe:steampipe@steampipe:9193/steampipe"
POWERPIPE_BASE_URL: "https://dashboards.example.com"
volumes:
- powerpipe-workspace:/workspace
depends_on:
steampipe:
condition: service_healthy

nginx:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
depends_on:
- powerpipe

volumes:
steampipe-data:
powerpipe-workspace:
```

## Grafana

Embed Powerpipe dashboards in Grafana using the [Text panel](https://grafana.com/docs/grafana/latest/panels-visualizations/visualizations/text/) with an iframe, or use the [Infinity datasource](https://grafana.com/grafana/plugins/yesoreyeram-infinity-datasource/) to query benchmark JSON exports.

### Iframe embed

In a Grafana Text panel (HTML mode):

```html
<iframe
src="http://powerpipe:9033/aws_compliance.benchmark.cis_aws_foundations_benchmark_v300"
width="100%"
height="800px"
frameborder="0">
</iframe>
```

> **Note:** Grafana must have `security.allow_embedding = true` in `grafana.ini`, and Powerpipe must be reachable from the Grafana container.

### Compose with Grafana

```yaml
# docker-compose-grafana.yml
services:
steampipe:
image: ghcr.io/devops-ia/steampipe:2.4.1
command: ["steampipe", "service", "start", "--foreground", "--database-listen", "network"]
environment:
STEAMPIPE_DATABASE_PASSWORD: steampipe
volumes:
- steampipe-data:/home/steampipe/.steampipe
healthcheck:
test: ["CMD", "pg_isready", "-h", "localhost", "-p", "9193", "-U", "steampipe"]
interval: 10s
timeout: 5s
retries: 10
start_period: 30s

powerpipe:
image: ghcr.io/devops-ia/powerpipe:1.5.1
environment:
POWERPIPE_DATABASE: "postgresql://steampipe:steampipe@steampipe:9193/steampipe"
volumes:
- powerpipe-workspace:/workspace
depends_on:
steampipe:
condition: service_healthy

grafana:
image: grafana/grafana:latest
ports:
- "3000:3000"
environment:
GF_SECURITY_ALLOW_EMBEDDING: "true"
volumes:
- grafana-data:/var/lib/grafana

volumes:
steampipe-data:
powerpipe-workspace:
grafana-data:
```

## CI/CD — benchmark exports

Export benchmark results as JSON for integration with CI pipelines or reporting tools:

```bash
# GitHub Actions — run compliance check on schedule
docker run --rm \
-v "$HOME/.aws:/home/powerpipe/.aws:ro" \
-v "$PWD/workspace:/workspace" \
-e POWERPIPE_DATABASE="${STEAMPIPE_CONNECTION_STRING}" \
ghcr.io/devops-ia/powerpipe:1.5.1 \
powerpipe benchmark run aws_compliance.benchmark.cis_aws_foundations_benchmark_v300 \
--export /workspace/results.json \
--output brief
```

Parse the JSON output with standard tools:

```bash
# Count failed controls
jq '[.groups[].controls[] | select(.status == "alarm")] | length' workspace/results.json
```
Loading
Loading