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
74 changes: 74 additions & 0 deletions .github/workflows/docker-rds-images.yml
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ jobs:
permissions:
contents: read
packages: write
id-token: write
strategy:
fail-fast: false
matrix:
Expand Down Expand Up @@ -170,10 +171,83 @@ jobs:

- name: Create manifest list and push
working-directory: /tmp/digests
id: manifest
run: |
set -euo pipefail
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
$(printf '${{ env.IMAGE_BASE }}@sha256:%s ' *)
# Resolve the digest of the freshly-pushed manifest list so
# cosign can sign the immutable reference rather than a tag
# that could be moved out from under us.
DIGEST=$(docker buildx imagetools inspect \
"${IMAGE_BASE}:${{ steps.meta.outputs.version }}" \
--format '{{ .Manifest.Digest }}')
echo "digest=$DIGEST" >> "$GITHUB_OUTPUT"

- name: Inspect image
run: |
docker buildx imagetools inspect ${{ env.IMAGE_BASE }}:${{ steps.meta.outputs.version }}

- name: Install cosign
uses: sigstore/cosign-installer@d7d6bc7722e3daa8354c50bcb52f4837da5e9b6a # v3.8.1
with:
cosign-release: v2.4.1

- name: Sign image with cosign (keyless, GitHub OIDC)
env:
COSIGN_EXPERIMENTAL: "1"
run: |
cosign sign --yes "${IMAGE_BASE}@${{ steps.manifest.outputs.digest }}"

scan:
if: github.event_name != 'pull_request'
runs-on: ubuntu-24.04
needs: merge
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot Apr 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: The Trivy gate runs after image publish/sign, so vulnerable images can still be released before the failure is detected.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .github/workflows/docker-rds-images.yml, line 205:

<comment>The Trivy gate runs after image publish/sign, so vulnerable images can still be released before the failure is detected.</comment>

<file context>
@@ -170,10 +171,83 @@ jobs:
+  scan:
+    if: github.event_name != 'pull_request'
+    runs-on: ubuntu-24.04
+    needs: merge
+    permissions:
+      contents: read
</file context>
Fix with Cubic

permissions:
contents: read
packages: read
strategy:
fail-fast: false
matrix:
target:
- { engine: postgres, version: "13" }
- { engine: postgres, version: "14" }
- { engine: postgres, version: "15" }
- { engine: postgres, version: "16" }
- { engine: mysql, version: "8.0" }
- { engine: mariadb, version: "10.6" }
- { engine: mariadb, version: "10.11" }
- { engine: mariadb, version: "11.4" }
env:
IMAGE_BASE: ghcr.io/${{ github.repository_owner }}/fakecloud-${{ matrix.target.engine }}

steps:
- name: Log in to GitHub Container Registry
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Resolve short SHA
id: sha
run: echo "short=$(echo "${{ github.sha }}" | cut -c1-7)" >> "$GITHUB_OUTPUT"

- name: Extract metadata
id: meta
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5
with:
images: ${{ env.IMAGE_BASE }}
tags: |
type=semver,pattern=${{ matrix.target.version }}-{{version}}
type=raw,value=${{ matrix.target.version }}-dev-${{ steps.sha.outputs.short }},enable=${{ github.event_name == 'workflow_dispatch' }}

- name: Trivy vulnerability scan
uses: aquasecurity/trivy-action@6c175e9c4083a92bbca2f9724c8a5e33bc2d97a5 # 0.30.0
with:
image-ref: ${{ env.IMAGE_BASE }}:${{ steps.meta.outputs.version }}
format: table
exit-code: '1'
ignore-unfixed: true
vuln-type: os,library
severity: CRITICAL,HIGH
52 changes: 52 additions & 0 deletions .github/workflows/docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ jobs:
permissions:
contents: read
packages: write
id-token: write

steps:
- name: Download digests
Expand Down Expand Up @@ -105,11 +106,62 @@ jobs:
type=sha

- name: Create manifest list and push
id: manifest
working-directory: /tmp/digests
run: |
set -euo pipefail
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
$(printf '${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@sha256:%s ' *)
DIGEST=$(docker buildx imagetools inspect \
"${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }}" \
--format '{{ .Manifest.Digest }}')
echo "digest=$DIGEST" >> "$GITHUB_OUTPUT"

- name: Inspect image
run: |
docker buildx imagetools inspect ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }}

- name: Install cosign
uses: sigstore/cosign-installer@d7d6bc7722e3daa8354c50bcb52f4837da5e9b6a # v3.8.1
with:
cosign-release: v2.4.1

- name: Sign image with cosign (keyless, GitHub OIDC)
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot Apr 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: The vulnerability gate runs after cosign signing, so images can be signed before Trivy blocks the release. Move signing behind the scan gate (or scan before signing) so only passing images are signed.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .github/workflows/docker.yml, line 129:

<comment>The vulnerability gate runs after cosign signing, so images can be signed before Trivy blocks the release. Move signing behind the scan gate (or scan before signing) so only passing images are signed.</comment>

<file context>
@@ -105,11 +106,62 @@ jobs:
+        with:
+          cosign-release: v2.4.1
+
+      - name: Sign image with cosign (keyless, GitHub OIDC)
+        env:
+          COSIGN_EXPERIMENTAL: "1"
</file context>
Fix with Cubic

env:
COSIGN_EXPERIMENTAL: "1"
run: |
cosign sign --yes "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.manifest.outputs.digest }}"

scan:
runs-on: ubuntu-24.04
needs: merge
permissions:
contents: read
packages: read

steps:
- name: Log in to GitHub Container Registry
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata
id: meta
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=semver,pattern={{version}}
type=raw,value=latest,enable={{is_default_branch}}

- name: Trivy vulnerability scan
uses: aquasecurity/trivy-action@6c175e9c4083a92bbca2f9724c8a5e33bc2d97a5 # 0.30.0
with:
image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }}
format: table
exit-code: '1'
ignore-unfixed: true
vuln-type: os,library
severity: CRITICAL,HIGH
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,18 @@ Use fakecloud as a local AWS emulator for integration tests.
- **[Reference](https://fakecloud.dev/docs/reference)** — configuration, introspection endpoints, persistence
- **[Blog](https://fakecloud.dev/blog)** — essays and hot takes on testing, AWS, and AI-assisted development

### Verifying image signatures

Every published image (`fakecloud`, `fakecloud-postgres`, `fakecloud-mysql`, `fakecloud-mariadb`) is Trivy-scanned and cosign-signed via GitHub OIDC. Verify before pulling:

```sh
cosign verify ghcr.io/faiscadev/fakecloud:latest \
--certificate-identity-regexp '^https://github\.com/faiscadev/fakecloud/' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com
```

See [security docs](https://fakecloud.dev/docs/reference/security/#image-supply-chain-cosign--trivy) for details.

## Contributing

Contributions welcome. Fork, branch, write tests, open a PR.
Expand Down
17 changes: 17 additions & 0 deletions website/content/docs/reference/security.md
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,23 @@ AWS_ACCESS_KEY_ID=<alice-akid> AWS_SECRET_ACCESS_KEY=<alice-secret> \
# -> AccessDeniedException
```

## Image supply-chain (cosign + Trivy)

Every published container image — `ghcr.io/faiscadev/fakecloud` and the prebuilt RDS support images (`fakecloud-postgres`, `fakecloud-mysql`, `fakecloud-mariadb`) — is:

1. **Scanned** by [Trivy](https://github.com/aquasecurity/trivy) for `CRITICAL`/`HIGH` OS and library vulnerabilities (`ignore-unfixed: true`). The release fails closed if any are found.
2. **Signed** with [cosign](https://github.com/sigstore/cosign) keyless mode using the GitHub Actions OIDC token, so attestations are anchored to the workflow that built the image — no key management, no detached secret.

To verify an image before pulling:

```bash
cosign verify ghcr.io/faiscadev/fakecloud-postgres:16-0.13.1 \
--certificate-identity-regexp '^https://github\.com/faiscadev/fakecloud/' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com
```

Same shape works for `fakecloud-mysql`, `fakecloud-mariadb`, and the main `fakecloud` image. A successful verification means the image was built by a workflow run in the `faiscadev/fakecloud` repository — not republished by anyone else.

## See also

- [Limitations](@/docs/reference/limitations.md) — what fakecloud doesn't do at all
Expand Down
Loading