Skip to content
Merged
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
1a43b34
fix(containers): bind provenance to pinned bases
seonghobae Aug 4, 2026
0d17e7f
ci: materialize PR 1203 governance test fix
seonghobae Aug 4, 2026
982fb32
ci: trigger PR 1203 governance fix from review state
seonghobae Aug 4, 2026
991c760
test(governance): align Strix cryptography security pin
github-actions[bot] Aug 4, 2026
636eac1
ci: revalidate container provenance on current head
seonghobae Aug 4, 2026
c700e18
docs(containers): define pinned provenance contract
seonghobae Aug 4, 2026
e2a5eb1
Merge branch 'develop' into codex/docker-base-current
opencode-agent[bot] Aug 4, 2026
c547b73
ci: materialize container provenance review fixes
seonghobae Aug 4, 2026
7077d23
ci: add bounded PR 1203 provenance repair
seonghobae Aug 5, 2026
3e5703c
ci: correct PR 1203 provenance finalizer
seonghobae Aug 5, 2026
f7a69f4
ci: sanitize PR 1203 generated regex literal
seonghobae Aug 5, 2026
b5baad6
ci: anchor PR 1203 changelog insertion at first heading
seonghobae Aug 5, 2026
0f03861
ci: rebind PR 1203 finalizer to corrected helper
seonghobae Aug 5, 2026
acf66d0
ci: use the canonical backend test lock for PR 1203
seonghobae Aug 5, 2026
bd3cceb
test(container): lock provenance dependency floors
seonghobae Aug 5, 2026
21949d6
docs(container): ground provenance contract in current standards
seonghobae Aug 5, 2026
f34139d
ci(container): remove completed PR finalizer
seonghobae Aug 5, 2026
23ac637
ci(container): remove completed repair script
seonghobae Aug 5, 2026
cd1cfd8
test(container): bind dependency pins to generated locks
seonghobae Aug 5, 2026
a45eba2
ci: run verified PR 1203 provenance finalizer
seonghobae Aug 5, 2026
37a166f
chore(ci): remove PR-specific provenance finalizer
seonghobae Aug 6, 2026
35b6780
Merge branch 'develop' into codex/docker-base-current
opencode-agent[bot] Aug 6, 2026
b1eda1f
test(container): parse dependency pin evidence structurally
seonghobae Aug 6, 2026
d16e41d
docs(container): align provenance and dependency contracts
seonghobae Aug 6, 2026
f2c63f7
fix(container): require derived OCI base metadata
seonghobae Aug 6, 2026
92e7692
Merge branch 'develop' into codex/docker-base-current
opencode-agent[bot] Aug 6, 2026
197bce1
fix(container): require frontend OCI base metadata
seonghobae Aug 6, 2026
7758740
ci: verify and remove PR 1203 temporary machinery
seonghobae Aug 6, 2026
8cd0471
Merge branch 'develop' into codex/docker-base-current
opencode-agent[bot] Aug 7, 2026
70fae9c
chore(ci): remove completed PR 1203 cleanup workflow
seonghobae Aug 7, 2026
9faaa7d
fix(containers): synchronize OCI base defaults
seonghobae Aug 7, 2026
869ce40
fix(containers): synchronize frontend OCI base defaults
seonghobae Aug 7, 2026
b694980
Merge branch 'develop' into codex/docker-base-current
opencode-agent[bot] Aug 7, 2026
cb3946c
Merge branch 'develop' into codex/docker-base-current
opencode-agent[bot] Aug 7, 2026
a6cce6f
Consolidate current container pins with provenance contract
seonghobae Aug 14, 2026
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
102 changes: 102 additions & 0 deletions .github/workflows/cleanup-pr1203-provenance-finalizer.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
name: Cleanup PR 1203 provenance machinery

on:
push:
branches:
- codex/docker-base-current
paths:
- .github/workflows/cleanup-pr1203-provenance-finalizer.yml

permissions:
contents: write
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed

concurrency:
group: cleanup-pr1203-provenance-finalizer
cancel-in-progress: false

env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
PYTHONWARNINGS: error

jobs:
verify-and-clean:
if: github.actor != 'github-actions[bot]'
runs-on: ubuntu-24.04
timeout-minutes: 45
steps:
- name: Harden runner
uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0
with:
egress-policy: audit

- name: Check out exact trigger
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
ref: ${{ github.sha }}
fetch-depth: 2
persist-credentials: false

- name: Remove temporary machinery before verification
env:
EXPECTED_SHA: ${{ github.sha }}
shell: bash --noprofile --norc -e -o pipefail {0}
run: |
test "$(git rev-parse HEAD)" = "$EXPECTED_SHA"
rm -f \
.github/workflows/pr1203-finalize.yml \
scripts/ci/repair_pr_1203_provenance.py \
.github/workflows/cleanup-pr1203-provenance-finalizer.yml
git diff --check

- name: Set up Python
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: '3.14'
cache: pip
cache-dependency-path: backend/requirements-hashes.txt

- name: Install hash-locked backend dependencies
run: python -m pip install --disable-pip-version-check --require-hashes -r backend/requirements-hashes.txt

- name: Verify provenance and repository governance
working-directory: backend
run: |
python -m pytest -q \
tests/test_container_provenance_contract.py \
tests/test_release_governance.py \
tests/test_repo_hygiene.py
python -m ruff check \
tests/test_container_provenance_contract.py \
tests/test_release_governance.py \
tests/test_repo_hygiene.py

- name: Validate workflows and final diff
run: |
python - <<'PY'
from pathlib import Path
import yaml

for path in (
Path('.github/workflows/docker-publish.yml'),
):
yaml.safe_load(path.read_text(encoding='utf-8'))
PY
test ! -e .github/workflows/pr1203-finalize.yml
test ! -e scripts/ci/repair_pr_1203_provenance.py
test ! -e .github/workflows/cleanup-pr1203-provenance-finalizer.yml
git diff --check

- name: Publish verified cleanup
env:
PUSH_TOKEN: ${{ github.token }}
shell: bash --noprofile --norc -e -o pipefail {0}
run: |
git config user.name 'github-actions[bot]'
git config user.email '41898282+github-actions[bot]@users.noreply.github.com'
git add -A
git diff --cached --quiet && exit 1
git commit -m 'chore(ci): remove completed PR 1203 machinery'
auth_header="$(printf 'x-access-token:%s' "$PUSH_TOKEN" | base64 | tr -d '\n')"
echo "::add-mask::$auth_header"
git -c http.extraheader="AUTHORIZATION: basic ${auth_header}" \
push origin 'HEAD:codex/docker-base-current'
60 changes: 48 additions & 12 deletions .github/workflows/docker-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,21 @@ jobs:
- component: backend
image: ai_email_client-backend
dockerfile: Dockerfile
base_dockerfile: Dockerfile
context: .
build_args: |
BUILDKIT_INLINE_CACHE=1
- component: naruon
image: naruon
dockerfile: Dockerfile
base_dockerfile: Dockerfile
context: .
build_args: |
BUILDKIT_INLINE_CACHE=1
- component: frontend
image: ai_email_client-frontend
dockerfile: frontend/Dockerfile
base_dockerfile: frontend/Dockerfile
context: .
build_args: |
BUILDKIT_INLINE_CACHE=1
Expand All @@ -62,9 +65,28 @@ jobs:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0

- name: Resolve pinned Ollama base manifest
if: matrix.component == 'naruon'
run: |
base_image="$(awk 'toupper($1) == "FROM" { print $2; exit }' Dockerfile.ollama)"
if ! printf '%s\n' "$base_image" | grep -Eq '^ollama/ollama@sha256:[0-9a-f]{64}$'; then
printf '::error file=Dockerfile.ollama,line=1::Expected an exact ollama/ollama sha256 base pin; found %s\n' "$base_image"
exit 1
fi
printf 'Resolving pinned Ollama base manifest: %s\n' "$base_image"
manifest_output="$(docker buildx imagetools inspect "$base_image")"
printf '%s\n' "$manifest_output"
for platform in linux/amd64 linux/arm64; do
if ! printf '%s\n' "$manifest_output" | grep -Eq "^[[:space:]]*Platform:[[:space:]]+${platform}[[:space:]]*$"; then
printf '::error file=Dockerfile.ollama,line=1::Pinned Ollama manifest is missing %s\n' "$platform"
exit 1
fi
done

- name: Prepare OCI annotation values
id: oci
env:
BASE_DOCKERFILE: ${{ matrix.base_dockerfile }}
GIT_REF_NAME: ${{ github.ref_name }}
IMAGE_COMPONENT: ${{ matrix.component }}
IMAGE_NAME: ${{ matrix.image }}
Expand All @@ -74,24 +96,29 @@ jobs:
version="$(cat VERSION)"
created="$(date -u +'%Y-%m-%dT%H:%M:%SZ')"
vendor="${REPOSITORY%%/*}"
base_reference="$(awk 'toupper($1) == "FROM" { print $2; exit }' "$BASE_DOCKERFILE")"
if ! printf '%s\n' "$base_reference" | grep -Eq '^[A-Za-z0-9._/-]+:[A-Za-z0-9._-]+@sha256:[0-9a-f]{64}$'; then
printf '::error file=%s,line=1::Expected an exact tagged sha256 base pin; found %s\n' "$BASE_DOCKERFILE" "$base_reference"
exit 1
fi
base_digest="${base_reference##*@}"
base_repository="${base_reference%@*}"
case "$base_repository" in
*/*) base_name="$base_reference" ;;
*) base_name="docker.io/library/$base_reference" ;;
esac
case "$IMAGE_COMPONENT" in
frontend)
title="naruon frontend"
description="Naruon Next.js frontend runtime image"
base_digest="sha256:191ef878ecb351d68b78219593de18bd8942afd59af59f29960dc4b24805a3f1"
base_name="docker.io/library/node:26-slim@${base_digest}"
;;
backend)
title="naruon backend"
description="Naruon FastAPI backend runtime image"
base_digest="sha256:44dd04494ee8f3b538294360e7c4b3acb87c8268e4d0a4828a6500b1eff50061"
base_name="docker.io/library/python:3.14-slim@${base_digest}"
;;
*)
title="naruon"
description="Naruon combined FastAPI and Next.js runtime image"
base_digest="sha256:44dd04494ee8f3b538294360e7c4b3acb87c8268e4d0a4828a6500b1eff50061"
base_name="docker.io/library/python:3.14-slim@${base_digest}"
;;
esac
{
Expand Down Expand Up @@ -156,18 +183,21 @@ jobs:
- component: backend
image: ai_email_client-backend
dockerfile: Dockerfile
base_dockerfile: Dockerfile
context: .
build_args: |
BUILDKIT_INLINE_CACHE=1
- component: naruon
image: naruon
dockerfile: Dockerfile
base_dockerfile: Dockerfile
context: .
build_args: |
BUILDKIT_INLINE_CACHE=1
- component: frontend
image: ai_email_client-frontend
dockerfile: frontend/Dockerfile
base_dockerfile: frontend/Dockerfile
context: .
build_args: |
BUILDKIT_INLINE_CACHE=1
Expand Down Expand Up @@ -200,6 +230,7 @@ jobs:
- name: Prepare OCI annotation values
id: oci
env:
BASE_DOCKERFILE: ${{ matrix.base_dockerfile }}
GIT_REF_NAME: ${{ github.ref_name }}
IMAGE_COMPONENT: ${{ matrix.component }}
IMAGE_NAME: ${{ matrix.image }}
Expand All @@ -210,24 +241,29 @@ jobs:
version="${VERSION_VALUE:-$(cat VERSION)}"
created="$(date -u +'%Y-%m-%dT%H:%M:%SZ')"
vendor="${REPOSITORY%%/*}"
base_reference="$(awk 'toupper($1) == "FROM" { print $2; exit }' "$BASE_DOCKERFILE")"
if ! printf '%s\n' "$base_reference" | grep -Eq '^[A-Za-z0-9._/-]+:[A-Za-z0-9._-]+@sha256:[0-9a-f]{64}$'; then
printf '::error file=%s,line=1::Expected an exact tagged sha256 base pin; found %s\n' "$BASE_DOCKERFILE" "$base_reference"
exit 1
fi
base_digest="${base_reference##*@}"
base_repository="${base_reference%@*}"
case "$base_repository" in
*/*) base_name="$base_reference" ;;
*) base_name="docker.io/library/$base_reference" ;;
esac
case "$IMAGE_COMPONENT" in
frontend)
title="naruon frontend"
description="Naruon Next.js frontend runtime image"
base_digest="sha256:191ef878ecb351d68b78219593de18bd8942afd59af59f29960dc4b24805a3f1"
base_name="docker.io/library/node:26-slim@${base_digest}"
;;
backend)
title="naruon backend"
description="Naruon FastAPI backend runtime image"
base_digest="sha256:44dd04494ee8f3b538294360e7c4b3acb87c8268e4d0a4828a6500b1eff50061"
base_name="docker.io/library/python:3.14-slim@${base_digest}"
;;
*)
title="naruon"
description="Naruon combined FastAPI and Next.js runtime image"
base_digest="sha256:44dd04494ee8f3b538294360e7c4b3acb87c8268e4d0a4828a6500b1eff50061"
base_name="docker.io/library/python:3.14-slim@${base_digest}"
;;
esac
{
Expand Down
13 changes: 9 additions & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Stage 1: Backend runtime for local Compose and backend-only deployments
FROM python:3.14-slim@sha256:b877e50bd90de10af8d82c57a022fc2e0dc731c5320d762a27986facfc3355c1 AS backend-runtime
FROM python:3.14-slim@sha256:cea0e6040540fb2b965b6e7fb5ffa00871e632eef63719f0ea54bca189ce14a6 AS backend-runtime
WORKDIR /app

ENV PYTHONDONTWRITEBYTECODE=1
Expand All @@ -25,7 +25,7 @@ EXPOSE 8000
CMD ["python", "scripts/start_backend.py", "--host", "0.0.0.0", "--port", "8000"]

# Stage 2: Build Frontend
FROM node:26-slim@sha256:ffc78385a788964bb3cbab5e434ff79a10bdc25b8ae6db03fe5fe6cb14053c09 AS frontend-builder
FROM node:26-slim@sha256:715e55e4b84e4bb0ff48e49b398a848f08e55daed8eb6a0ea1839ae53bc57583 AS frontend-builder
WORKDIR /app
ENV NPM_CONFIG_UPDATE_NOTIFIER=false
ENV PNPM_VERSION=11.5.3
Expand Down Expand Up @@ -63,8 +63,13 @@ ARG OCI_IMAGE_LICENSES="LicenseRef-Naruon-Proprietary"
ARG OCI_IMAGE_REF_NAME=""
ARG OCI_IMAGE_TITLE="naruon"
ARG OCI_IMAGE_DESCRIPTION="Naruon combined FastAPI and Next.js runtime image"
ARG OCI_IMAGE_BASE_DIGEST="sha256:44dd04494ee8f3b538294360e7c4b3acb87c8268e4d0a4828a6500b1eff50061"
ARG OCI_IMAGE_BASE_NAME="docker.io/library/python:3.14-slim@sha256:44dd04494ee8f3b538294360e7c4b3acb87c8268e4d0a4828a6500b1eff50061"
ARG OCI_IMAGE_BASE_DIGEST
ARG OCI_IMAGE_BASE_NAME

# Base-image annotations are derived by the publishing workflow from the exact
# first FROM instruction. Missing values fail the build instead of silently
# publishing stale provenance copied into this Dockerfile.
RUN test -n "$OCI_IMAGE_BASE_DIGEST" && test -n "$OCI_IMAGE_BASE_NAME"

LABEL org.opencontainers.image.created="${OCI_IMAGE_CREATED}" \
org.opencontainers.image.authors="${OCI_IMAGE_AUTHORS}" \
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile.ollama
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM ollama/ollama@sha256:509fdf54e23bd50d87af646cb51c0a7a203d6a83cc4d6695b3b08c5be1c62c0a
FROM ollama/ollama@sha256:6345fbc18bd73a1e16404be681dbc6fd291a027cab43ed541abe78c4c81051b0

ENV OLLAMA_MODELS=/usr/share/ollama/.ollama/models

Expand Down
Loading
Loading