Skip to content
Closed
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
47 changes: 39 additions & 8 deletions .github/workflows/bakery-build-native.yml
Original file line number Diff line number Diff line change
Expand Up @@ -456,8 +456,17 @@ jobs:
# name-free `repo@sha256:...` entry per target -- all of them coexist,
# unlike tags. wizcli's `extract` driver reads the local store, so it can
# only resolve every target once Test has warmed it.
- name: Scan
if: ${{ inputs.push && steps.filter-steps.outputs.wiz-auth == 'true' }}
# Production builds scan only the latest version of each image, now that the
# backlog has been scanned once; development builds keep scanning every push.
# Gated here rather than by passing `--latest` to the scan: this job is already
# pinned to one version, so `--latest` combined with that pin resolved to an
# empty target set on every non-latest version and exited 1, which
# continue-on-error then hid behind a red annotation on an otherwise green job.
# matrix.img.latest comes from `bakery ci matrix`, so the "is this the latest
# version" decision is made once, in one place.
- name: Wiz Scan
if: ${{ inputs.push && steps.filter-steps.outputs.wiz-auth == 'true'
&& (inputs.dev-versions == 'only' || matrix.img.latest) }}
continue-on-error: true
env:
IMAGE_NAME: ${{ matrix.img.image }}
Expand All @@ -479,11 +488,6 @@ jobs:
[[ -n "$WIZ_POLICY_ID" ]] && POLICY_FLAGS=(--policies "$WIZ_POLICY_ID")
PROJECT_FLAGS=()
[[ -n "$WIZ_PROJECT_ID" ]] && PROJECT_FLAGS=(--projects "$WIZ_PROJECT_ID")
# Production builds (dev-versions != only) scan only the --latest
# version of each image now that the backlog has been scanned once.
# Development builds keep scanning every push.
LATEST_FLAGS=()
[[ "$DEV_VERSIONS" != "only" ]] && LATEST_FLAGS=(--latest)
WIZCLI_PATH=${GITHUB_WORKSPACE}/tools/wizcli \
bakery wizcli scan \
--image-name "^${IMAGE_NAME}$" \
Expand All @@ -494,9 +498,36 @@ jobs:
"${DEV_SPEC_FLAGS[@]}" \
"${POLICY_FLAGS[@]}" \
"${PROJECT_FLAGS[@]}" \
"${LATEST_FLAGS[@]}" \
--metadata-file "./${IMAGE_NAME}-${IMAGE_VERSION}-${NORMALIZED_PLATFORM}-metadata.json" \
--context "$CONTEXT"

- name: Setup trivy
if: ${{ inputs.push && matrix.img.latest }}
uses: "posit-dev/images-shared/setup-trivy@main"

# After Test for the same reason the Wiz scan is: only Test's `docker run`
# makes every target addressable locally. Scanning earlier silently pulled
# and scanned the published image instead of the one just built.
- name: Trivy Scan
if: ${{ inputs.push && matrix.img.latest }}
continue-on-error: true
env:
IMAGE_NAME: ${{ matrix.img.image }}
IMAGE_VERSION: ${{ matrix.img.version }}
DEV_VERSIONS: ${{ inputs.dev-versions }}
MATRIX_VERSIONS: ${{ inputs.matrix-versions }}
NORMALIZED_PLATFORM: ${{ steps.normalize-platform.outputs.platform }}
CONTEXT: ${{ inputs.context }}
run: |
bakery trivy scan \
--image-name "^${IMAGE_NAME}$" \
--image-version "$IMAGE_VERSION" \
--image-platform "$NORMALIZED_PLATFORM" \
--dev-versions "$DEV_VERSIONS" \
--matrix-versions "$MATRIX_VERSIONS" \
--metadata-file "./${IMAGE_NAME}-${IMAGE_VERSION}-${NORMALIZED_PLATFORM}-metadata.json" \
--context "$CONTEXT"

- name: Upload Metadata
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@ jobs:
- name: Setup wizcli
uses: ./setup-wizcli

- name: Setup trivy
uses: ./setup-trivy

- name: Setup ORAS CLI
uses: oras-project/setup-oras@1d808f7d7f6995cc68b7bf507bfe5c5446e1dc9d # v2.0.1

Expand Down Expand Up @@ -164,6 +167,7 @@ jobs:
contents: read
packages: write
id-token: write
security-events: write

uses: "./.github/workflows/bakery-build-native.yml"
secrets:
Expand All @@ -181,6 +185,7 @@ jobs:
permissions:
contents: read
packages: write
security-events: write
uses: "./.github/workflows/bakery-build-pr.yml"
with:
version: ${{ github.head_ref || github.ref_name }}
Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ Run `bakery --help` and `bakery <command> --help` for full command reference.
Commands have aliases: `build`/`b`, `create`/`c`, `run`/`r`, `update`/`u`, `remove`/`rm`.

Key commands for product repos: `bakery build`, `bakery build --plan`, `bakery dgoss run`,
`bakery update files`, `bakery create version`, `bakery ci matrix`.
`bakery trivy scan`, `bakery update files`, `bakery create version`, `bakery ci matrix`.

## Image Templating System

Expand Down
2 changes: 1 addition & 1 deletion posit-bakery/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ Full documentation is available at **[posit-dev.github.io/images-shared](https:/
| [dgoss](https://github.com/goss-org/goss#installation) | `bakery dgoss run` | Test container images for expected content & behavior |
| [hadolint](https://github.com/hadolint/hadolint#install) | `bakery hadolint run` | Lint Dockerfile/Containerfile |
| [openscap](https://static.open-scap.org/) | to be implemented | Scan container images for secure configuration and vulnerabilities |
| [trivy](https://trivy.dev/docs/latest/getting-started/) | to be implemented | Scan container images for vulnerabilities |
| [trivy](https://trivy.dev/docs/latest/getting-started/) | `bakery trivy scan` | Scan container images for vulnerabilities |
| [wizcli](https://www.wiz.io/lp/wiz-cli) | `bakery wizcli scan` | Scan container images for vulnerabilities |

## Installation
Expand Down
6 changes: 3 additions & 3 deletions posit-bakery/docs/architecture.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ flowchart TD
results[/"Test & Scan results"/]

trivy[[trivy]]
runTrivy[[bakery trivy run]]
runTrivy[[bakery trivy scan]]
runTrivy --> trivy
image -.-> trivy -.-> results

Expand All @@ -244,8 +244,8 @@ flowchart TD
class trivy,openscap,wizcli external

%% Mark what we are working on and is in flight %%
class inprogress,trivy todo
class openscap,results todo
class inprogress todo
class openscap todo
```

### Publish
Expand Down
27 changes: 27 additions & 0 deletions posit-bakery/docs/configuration.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -666,6 +666,33 @@ images:
- linux/arm64
```

#### TrivyOptions

A TrivyOption configures [Trivy](https://trivy.dev/docs/latest/getting-started/) vulnerability scanning for an image target.

Trivy options can be set in the `options` array of an [Image](#image) or an [ImageVariant](#imagevariant). When both are present, the variant's options are merged over the image's options, with any field not explicitly set on the variant inheriting the image-level value. Scanning runs via `bakery trivy scan`, which writes SARIF results to `results/trivy/`. CLI flags (`--severity`, `--fail-on-severity`, `--disabled-scanners`, `--timeout`) take precedence over these options when both are set.

| Field | Description | Default Value | Example |
|-----------------------------------------|-------------------------------------------------------------------|-----------------|---------------------------|
| `tool`<br/>*"trivy" literal string* | *(Required)* The name of the tool. | | `trivy` |
| `severity`<br/>*string array* | Severities to report (e.g. HIGH, CRITICAL). | Trivy default | `["HIGH", "CRITICAL"]` |
| `failOnSeverity`<br/>*string array* | Severities that fail the scan if found. Unset means never fail. | Never fails | `["CRITICAL"]` |
| `disabledScanners`<br/>*string array* | Scanners to disable (e.g. secret, license, misconfig). | Trivy default | `["secret"]` |
| `timeout`<br/>*string* | Timeout for the scan (e.g. 1h, 10m). | Trivy default | `"10m"` |

##### Example TrivyOptions

```yaml
images:
- name: workbench
options:
- tool: trivy
severity: ["HIGH", "CRITICAL"]
failOnSeverity: ["CRITICAL"]
disabledScanners: ["secret"]
timeout: "10m"
```

### DevBuildSpec

A DevBuildSpec is a typed payload passed to the `--dev-spec` CLI option to configure development (daily) version builds. It supports either a dispatch-pinned version or a branch-targeted discovery build. At least one of `version` or `release_branch` must be set.
Expand Down
3 changes: 2 additions & 1 deletion posit-bakery/docs/index.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ Bakery is a CLI tool that binds together various tools to manage a matrixed buil
| [dgoss](https://github.com/goss-org/goss#installation) | `bakery dgoss run` | Test container images for expected content & behavior |
| [hadolint](https://github.com/hadolint/hadolint#install) | `bakery hadolint run` | Lint Containerfiles for best practices |
| [oras](https://oras.land/) | `bakery imagetools merge` | Merge multi-platform images into an OCI index |
| [trivy](https://trivy.dev/docs/latest/getting-started/) | `bakery trivy scan` | Scan container images for vulnerabilities |
| [wizcli](https://www.wiz.io/) | `bakery wizcli scan` | Scan container images for vulnerabilities |

::: {.callout-note}
Additional tool integrations (trivy, openscap) are planned. See the [architecture diagrams](architecture.qmd) for the full roadmap.
Additional tool integrations (openscap) are planned. See the [architecture diagrams](architecture.qmd) for the full roadmap.
:::

## Installation
Expand Down
44 changes: 30 additions & 14 deletions posit-bakery/posit_bakery/cli/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,27 +43,43 @@ def exit_if_no_targets(config: "BakeryConfig", settings: "BakerySettings") -> No
detail = f" matching {active}" if active else ""
stderr_console.print(
f"❌ No image targets{detail}. Check the --image-name, --image-version, "
"--image-variant, --image-os, and --image-platform filters along with the "
"--dev-versions/--matrix-versions selection.",
"--image-variant, --image-os, --image-platform, and --latest filters along "
"with the --dev-versions/--matrix-versions selection.",
style="error",
)
raise typer.Exit(code=1)


def _describe_active_filters(settings: "BakerySettings") -> str:
"""Render the set filters as a human-readable ``--flag value`` list."""
"""Render the active filters as a human-readable ``--flag value`` list.

Only lists filters the caller actually set. ``--latest`` is included
because it is the one narrowing policy filter whose default (``False``)
does not narrow, so seeing it here always means the caller asked for it --
and it is frequently the filter that emptied the selection while every
selector matched, which a selector-only message hid entirely.
``--dev-versions``/``--matrix-versions`` stay out: they default to
``exclude``, so echoing them would report flags the caller never passed.
"""
f = settings.filter
parts = [
f"--{name} {value!r}"
for name, value in (
("image-name", f.image_name),
("image-version", f.image_version),
("image-variant", f.image_variant),
("image-os", f.image_os),
("image-platform", f.image_platform),
)
if value
]
parts = []
for name, value in (
("image-name", f.image_name),
("image-version", f.image_version),
("image-variant", f.image_variant),
("image-os", f.image_os),
("image-platform", f.image_platform),
):
if not value:
continue
if isinstance(value, (list, tuple)):
# Render as the flag would be typed rather than as a Python list
# repr, which surfaced as "--image-platform ['linux/arm64']".
parts.extend(f"--{name} {v!r}" for v in value)
else:
parts.append(f"--{name} {value!r}")
if settings.latest:
parts.append("--latest")
return ", ".join(parts)


Expand Down
Loading
Loading