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
61 changes: 61 additions & 0 deletions .github/workflows/manual-smoke.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
name: Manual Compose smoke

on:
workflow_dispatch:
inputs:
candidate:
description: Tracked repository-relative release candidate JSON
required: true
type: string
profile:
description: Supported Compose profile
required: true
type: choice
options:
- aml-online-shop-compose-v1
inspection_only:
description: Explicitly inspect legacy-ineligible candidates
required: false
default: false
type: boolean

permissions:
contents: read

jobs:
smoke:
name: Manual Compose runtime smoke
runs-on: ubuntu-24.04
timeout-minutes: 45
env:
SMOKE_CANDIDATE: ${{ inputs.candidate }}
SMOKE_PROFILE: ${{ inputs.profile }}
SMOKE_INSPECTION_ONLY: ${{ toJSON(inputs.inspection_only) }}
SMOKE_COMMIT: ${{ github.sha }}
steps:
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
with:
ref: ${{ github.sha }}
fetch-depth: 0
persist-credentials: false
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
with:
python-version: '3.13'
- name: Build and install selected commit
run: |
python -m pip install build
python -m build --wheel
python -m pip install dist/*.whl
- name: Execute bounded smoke
run: python scripts/manual_smoke.py execute
- name: Finalize evidence and best-effort project cleanup
if: ${{ always() }}
run: python scripts/manual_smoke.py finalize
- name: Upload sanitized evidence
if: ${{ always() }}
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: compose-smoke-evidence
path: ${{ runner.temp }}/container-platform-smoke-evidence/report.json
retention-days: 7
if-no-files-found: error
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,3 +124,5 @@ Add `--registry` to inspect immutable manifest/config bytes and declared platfor
## Optional runtime smoke

[Bounded runtime smoke](docs/runtime-smoke.md) requires explicit `--execute`, consumes the rendered candidate snapshot and cleans up its unique Compose project. It checks service process state and a synthetic catalog/cart/checkout flow. Inspection-only baseline execution preserves legacy ineligibility. See the recorded live outcome and limitations; runtime success is separate from release approval and deployment authorization.

[Manual hosted smoke](docs/manual-smoke-workflow.md) adds a dispatch-only workflow with sanitized evidence and best-effort scoped recovery. Its first hosted baseline run remains pending default-branch workflow registration and owner dispatch; it is not a mandatory PR check.
49 changes: 49 additions & 0 deletions docs/manual-smoke-workflow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Manual hosted Compose smoke

`.github/workflows/manual-smoke.yml` supplies opt-in runtime evidence on an ephemeral `ubuntu-24.04` Linux/amd64 hosted runner. It has only `workflow_dispatch`, read-only repository permissions, pinned Actions, a 45-minute timeout and no cancellation concurrency policy. Existing PR checks are unchanged. No registry login, secrets, application image builds, publication or deployment are requested.

## Inputs and tested revision

- `candidate`: required repository-relative tracked regular file, for example `releases/baseline-2026-10-18.json`. Absolute/traversal paths, symlink files/ancestors, untracked files and content differing from the selected commit are rejected.
- `profile`: `aml-online-shop-compose-v1`, the only supported choice.
- `inspection_only`: boolean, default `false`. Helper parsing accepts only the exact strings `true` and `false` supplied through environment values.

The workflow's native branch/tag selection chooses the workflow revision. There is no separate code-ref input: checkout pins `github.sha`, includes full Git history and does not persist credentials. The wheel, candidate snapshot, profile and schema come from this commit. The helper checks installed module/resource bytes against Git objects, verifies local inventory objects, then calls the installed [bounded runner](runtime-smoke.md) with explicit execution opt-in. Runtime orchestration and its budgets are not duplicated or weakened. Inputs are never interpolated into shell code.

Ordinary mode requires successful offline validation. For the legacy baseline, explicit inspection-only is required. A successful runtime result then coexists with validation exit 1 and 12 `legacy_ineligible` failures; it does not grant approval or deployment authorization.

## Evidence and failure behavior

The sole uploaded artifact is `compose-smoke-evidence`, containing `report.json` at the predictable `container-platform-smoke-evidence/report.json` location under the runner temporary root. Retention is seven days. It includes tested full commit SHA, candidate path/byte SHA-256, profile/inspection mode, the sanitized runner result, original primary exit code and workflow cleanup verification. The job summary adds release ID, runtime/cleanup outcomes and offline eligibility. Candidate-controlled values are JSON-quoted and HTML-escaped; no raw values are printed as workflow commands.

Only this report is uploaded, never the workspace, cleanup state, raw Docker logs, cookies or environment. Missing/malformed reports create explicit execution/report failure evidence and cannot yield success. Preparation failures report stable diagnostics; identity fields that could not be established remain unavailable. Runtime nonzero exit codes remain primary even when report processing or cleanup also fails. Upload failures fail the job; the report's primary code describes runtime, not artifact-service availability. Consult the job conclusion as well as the evidence.

## Cancellation and cleanup

The runner retains its normal interruption cleanup. A minimal pre-mutation hook saves the exact generated project identity and Compose bytes after successful prerequisites/name-collision checks. An `always()` workflow step checks only that identity and performs bounded project-scoped cleanup if resources remain, then verifies absence of its containers, networks and volumes. Identity, commit and Compose-byte hash must agree before cleanup. It does not search projects by prefix, prune globally or delete cached images.

Best-effort recovery and upload cannot be guaranteed after forced cancellation, repeated interruption, job timeout, Engine failure or runner loss. Cancellation recovery has offline adapter coverage but has not been verified by a live cancellation experiment. Ephemeral-host disposal is separate from verified application cleanup. A successful ordinary run must contain successful runner cleanup plus verified workflow resource absence.

## Hosted acceptance: pending registration

As of 2026-10-23, this workflow is absent from the default branch's registered workflows. GitHub [requires the dispatch workflow to exist on the default branch](https://docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows#workflow_dispatch). No hosted runtime dispatch has been performed; prior local runtime evidence does not satisfy this criterion. No temporary PR/push runtime trigger or substitute workflow is used.

After owner review and merge register the workflow on `main`:

1. Dispatch the baseline with explicit inspection-only:

```text
gh workflow run manual-smoke.yml --repo DimitryZH/container-platform --ref main -f candidate=releases/baseline-2026-10-18.json -f profile=aml-online-shop-compose-v1 -f inspection_only=true
```

2. Find and inspect the actual dispatch run:

```text
gh run list --repo DimitryZH/container-platform --workflow manual-smoke.yml --event workflow_dispatch --limit 5
gh run view RUN_ID --repo DimitryZH/container-platform
gh run download RUN_ID --repo DimitryZH/container-platform --name compose-smoke-evidence
```

3. Confirm the intended tested SHA, candidate hash and exact images, all 12 service records, semantic assertions, runtime exit 0, successful runner cleanup, verified workflow resource absence and retained validation exit 1 with 12 legacy failures. Confirm artifact and summary availability. Record a concise hosted observation tied to the run URL; keep issue #15 open until this evidence is reviewed.

No hosted success, cancellation recovery or milestone completion is claimed before those checks occur.
2 changes: 2 additions & 0 deletions docs/roadmap.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ Invalid, incomplete, mutable, or unavailable releases cannot be presented as val

[Pull request checks](pull-request-validation.md) provide tests/package and new-candidate validation. [Offline Compose rendering](compose-rendering.md) provides deterministic configuration from digest-pinned candidates. An [opt-in bounded runtime runner](runtime-smoke.md) is available; its live result and limitations are recorded separately. Required-check settings are owner-configured; runner availability does not complete this milestone or prove baseline runtime compatibility.

A [manual hosted workflow](manual-smoke-workflow.md) is prepared; hosted baseline acceptance remains pending workflow registration on the default branch and an actual owner dispatch. It adds no mandatory runtime PR check and does not close this milestone.

### Scope

- add GitHub Actions checks for release-manifest pull requests;
Expand Down
Loading