diff --git a/.github/workflows/v1-consumer-example-smoke.yml b/.github/workflows/v1-consumer-example-smoke.yml new file mode 100644 index 00000000..e449033b --- /dev/null +++ b/.github/workflows/v1-consumer-example-smoke.yml @@ -0,0 +1,148 @@ +name: V1 Copy-Ready Consumer Qualification + +on: + pull_request: + paths: + - '.github/workflows/v1-consumer-example-smoke.yml' + - 'examples/github-action-consumer-v1.yml' + - 'examples/README.md' + - 'docs/GITHUB_ACTION.md' + push: + branches: [main] + paths: + - '.github/workflows/v1-consumer-example-smoke.yml' + - 'examples/github-action-consumer-v1.yml' + - 'examples/README.md' + - 'docs/GITHUB_ACTION.md' + workflow_dispatch: + +permissions: + contents: read + +jobs: + public-v1-action: + name: Public v1 Action / signed-custody verdict matrix + runs-on: ubuntu-24.04 + timeout-minutes: 20 + steps: + - name: Check out consumer repository + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + + - name: Obtain published immutable v1.0.0 binary and verify checksum + shell: bash + run: | + set -euo pipefail + tag=v1.0.0 + target=x86_64-unknown-linux-gnu + asset="execsurface-${tag}-${target}.tar.gz" + mkdir -p "$RUNNER_TEMP/v1-consumer-bin" + cd "$RUNNER_TEMP/v1-consumer-bin" + curl --fail --location --retry 3 --silent --show-error -O "https://github.com/AETHERXGLOBAL/execsurface/releases/download/${tag}/${asset}" + curl --fail --location --retry 3 --silent --show-error -O "https://github.com/AETHERXGLOBAL/execsurface/releases/download/${tag}/${asset}.sha256" + sha256sum -c "${asset}.sha256" + tar -xzf "$asset" + binary="$PWD/execsurface-${tag}-${target}/execsurface" + test "$("$binary" --version)" = "execsurface 1.0.0" + echo "EXECSURFACE_V1_BIN=$binary" >> "$GITHUB_ENV" + + - name: Prepare explicitly pinned baseline and policy + id: prepare + shell: bash + run: | + set -euo pipefail + "$EXECSURFACE_V1_BIN" doctor + "$EXECSURFACE_V1_BIN" learn --output v1-consumer-baseline.json -- /bin/bash -lc true + python3 - <<'PY' + import json, os + value = json.load(open("v1-consumer-baseline.json"))["baseline_digest"] + if not (isinstance(value, str) and value.startswith("sha256:") and len(value) == 71): + raise SystemExit("untrusted/malformed baseline digest") + with open(os.environ["GITHUB_OUTPUT"], "a") as output: + print("baseline_digest=" + value, file=output) + PY + printf '{"schema_version":2,"default_action":"review","rules":[]}\n' > v1-consumer-policy.json + printf '{"schema_version":2,"default_action":"review","rules":[{"id":"deny-added-exec","action":"block","match":{"change":"added","effect":"process_exec"}}]}\n' > v1-consumer-block-policy.json + echo "policy_digest=sha256:$(sha256sum v1-consumer-policy.json | awk '{print $1}')" >> "$GITHUB_OUTPUT" + echo "block_policy_digest=sha256:$(sha256sum v1-consumer-block-policy.json | awk '{print $1}')" >> "$GITHUB_OUTPUT" + sha256sum v1-consumer-baseline.json > "$RUNNER_TEMP/v1-baseline.sha256" + + - name: Stable v1 Action PASS + uses: AETHERXGLOBAL/execsurface@v1 + id: pass + with: + command: "true" + baseline: v1-consumer-baseline.json + policy: v1-consumer-policy.json + expected-baseline-digest: ${{ steps.prepare.outputs.baseline_digest }} + expected-policy-sha256: ${{ steps.prepare.outputs.policy_digest }} + require-custody: "true" + fail-on-review: "true" + upload-artifact: "false" + + - name: Stable v1 Action REVIEW — accepted only as explicitly configured + uses: AETHERXGLOBAL/execsurface@v1 + id: review + with: + command: "true; /bin/echo controlled-drift >/dev/null" + baseline: v1-consumer-baseline.json + policy: v1-consumer-policy.json + expected-baseline-digest: ${{ steps.prepare.outputs.baseline_digest }} + expected-policy-sha256: ${{ steps.prepare.outputs.policy_digest }} + require-custody: "true" + fail-on-review: "false" + upload-artifact: "false" + + - name: Stable v1 Action BLOCK — fail closed + uses: AETHERXGLOBAL/execsurface@v1 + id: block + continue-on-error: true + with: + command: "true; /bin/echo controlled-block >/dev/null" + baseline: v1-consumer-baseline.json + policy: v1-consumer-block-policy.json + expected-baseline-digest: ${{ steps.prepare.outputs.baseline_digest }} + expected-policy-sha256: ${{ steps.prepare.outputs.block_policy_digest }} + require-custody: "true" + upload-artifact: "false" + + - name: Stable v1 Action ERROR — fail closed on missing baseline + uses: AETHERXGLOBAL/execsurface@v1 + id: error + continue-on-error: true + with: + command: "true" + baseline: missing-v1-consumer-baseline.json + policy: v1-consumer-policy.json + expected-baseline-digest: ${{ steps.prepare.outputs.baseline_digest }} + expected-policy-sha256: ${{ steps.prepare.outputs.policy_digest }} + require-custody: "true" + upload-artifact: "false" + + - name: Assert verdicts and baseline immutability + shell: bash + env: + PASS_VERDICT: ${{ steps.pass.outputs.verdict }} + PASS_EXIT: ${{ steps.pass.outputs.exit-code }} + REVIEW_VERDICT: ${{ steps.review.outputs.verdict }} + REVIEW_EXIT: ${{ steps.review.outputs.exit-code }} + BLOCK_VERDICT: ${{ steps.block.outputs.verdict }} + BLOCK_EXIT: ${{ steps.block.outputs.exit-code }} + BLOCK_OUTCOME: ${{ steps.block.outcome }} + ERROR_VERDICT: ${{ steps.error.outputs.verdict }} + ERROR_EXIT: ${{ steps.error.outputs.exit-code }} + ERROR_OUTCOME: ${{ steps.error.outcome }} + run: | + set -euo pipefail + test "$PASS_VERDICT" = "pass" + test "$PASS_EXIT" = "0" + test "$REVIEW_VERDICT" = "review" + test "$REVIEW_EXIT" = "10" + test "$BLOCK_VERDICT" = "block" + test "$BLOCK_EXIT" = "20" + test "$BLOCK_OUTCOME" = "failure" + test "$ERROR_VERDICT" = "error" + test "$ERROR_EXIT" = "2" + test "$ERROR_OUTCOME" = "failure" + sha256sum -c "$RUNNER_TEMP/v1-baseline.sha256" diff --git a/README.md b/README.md index caf6e685..30768599 100644 --- a/README.md +++ b/README.md @@ -104,7 +104,9 @@ The generated workflow uses the stable v1 Action channel: AETHERXGLOBAL/execsurface@v1 ``` -Do not use `@main` as the normal consumer path. See the **[GitHub Action guide](docs/GITHUB_ACTION.md)**. +For a copy-ready, least-privilege Rust consumer with independent target-success gating and external baseline/policy custody pins, use **[the stable-v1 GitHub Action example](examples/github-action-consumer-v1.yml)**. For non-Rust projects, adapt the target command and learn the baseline under the same wrapper. + +Do not use `@main` or historical `@v0.1` as the default for new consumers. See the **[GitHub Action guide](docs/GITHUB_ACTION.md)**. If the wrapped command's own success matters—for example `cargo test`, `pytest` or a build—keep that command as its own CI gate as well. In v1.0, target exit/signal remains report metadata and does not by itself change the ExecSurface drift verdict. @@ -225,6 +227,7 @@ Key documents: - [Current Status](docs/STATUS.md) - [Five-Minute Start](docs/QUICKSTART_5_MIN.md) - [GitHub Action](docs/GITHUB_ACTION.md) +- [Current v1 vs historical examples](examples/README.md) - [Troubleshooting](docs/TROUBLESHOOTING.md) - [Independent Evaluation](docs/INDEPENDENT_EVALUATION.md) - [Technical Evaluation Pack](docs/TECHNICAL_EVALUATION.md) diff --git a/docs/EXAMPLES.md b/docs/EXAMPLES.md index ccef81be..528bdd3a 100644 --- a/docs/EXAMPLES.md +++ b/docs/EXAMPLES.md @@ -1,5 +1,7 @@ # ExecSurface Command Examples +**Current supported release:** ExecSurface `v1.0.0` on Linux x86_64, including GitHub Action `AETHERXGLOBAL/execsurface@v1`. For a copy-ready CI example, see [Stable v1 Consumer](../examples/github-action-consumer-v1.yml) and [example selection](../examples/README.md). Historical Alpha.5 Python/pytest recipes are evidence replay examples, not current installation instructions. + These are **illustrative command recipes**, not claims that ExecSurface has separately certified every ecosystem. ExecSurface observes a command on supported Linux x86_64. The project command itself remains your responsibility. diff --git a/docs/GITHUB_ACTION.md b/docs/GITHUB_ACTION.md index 3ce048e0..c00424f7 100644 --- a/docs/GITHUB_ACTION.md +++ b/docs/GITHUB_ACTION.md @@ -16,7 +16,16 @@ For maximum pinning after this release, use: AETHERXGLOBAL/execsurface@v1.0.0 ``` -Do not use `@main` as the normal consumer path. +Do not use `@main` or a historical Alpha channel as the normal consumer path. + +## Copy-ready current-v1 consumer workflow + +For a Rust repository, use the **[stable-v1 copy-ready workflow](../examples/github-action-consumer-v1.yml)**. It deliberately runs the target tests independently, then checks execution-surface drift with `@v1`, `require-custody: "true"`, fail-closed REVIEW and least-privilege permissions. + +Before adopting it, review and commit the policy and baseline, then configure the two **trusted repository variables** `EXECSURFACE_BASELINE_DIGEST` and `EXECSURFACE_POLICY_SHA256`. The values must come from trusted maintainer approval, not untrusted PR content. The baseline is learned using exactly the same `/bin/bash -lc` wrapper on a comparable Linux x86_64 environment; environmental differences may legitimately trigger REVIEW. Do not automatically rewrite the baseline to silence the result. + +The [v1 example qualification workflow](../.github/workflows/v1-consumer-example-smoke.yml) exercises the published `@v1` Action against PASS, REVIEW, BLOCK and ERROR with externally supplied custody pins. Its results are separate from the historic Alpha.5 Python/pytest example. + ## Minimal workflow @@ -114,4 +123,4 @@ ExecSurface does not require PR-comment write permission. A PASS means the recorded comparison and policy did not identify review/block execution-surface drift. It does not prove the target command succeeded, and it does not prove the program is safe. -See [Current Status](STATUS.md) for the current Alpha scope and declared limitations. +See [Current Status](STATUS.md) for the **stable v1.0.0 Linux x86_64/native-ptrace scope** and declared limitations. The old Alpha.5/Alpha.6 releases remain historical evidence, not current onboarding defaults. diff --git a/docs/README.md b/docs/README.md index b3a58329..785cd856 100644 --- a/docs/README.md +++ b/docs/README.md @@ -5,11 +5,13 @@ This directory separates **current public guidance** from **engineering evidence ## Current public product - [Current Status](STATUS.md) — authoritative public support, distribution and validation state. -- [Production Readiness](PRODUCTION_READINESS.md) — P9 evidence contract and v1.0 qualification gates; not a claim that v1.0 is already authorized. -- [Compatibility & Stability Contract](COMPATIBILITY.md) — P9.3 candidate v1 compatibility boundary and the executable evidence required before it may become stable. +- [Production Readiness](PRODUCTION_READINESS.md) — retained P9 qualification contract and evidence supporting the published bounded v1.0.0 release. +- [Compatibility & Stability Contract](COMPATIBILITY.md) — active stable-v1 compatibility boundary and its qualification evidence. - [Five-Minute Start](QUICKSTART_5_MIN.md) — shortest controlled PASS → REVIEW walkthrough. - [Self-Service Start](SELF_SERVICE_START.md) — installation and first-use path for independent users. -- [GitHub Action](GITHUB_ACTION.md) — CI integration and stable Action usage. +- [GitHub Action](GITHUB_ACTION.md) — current `@v1` CI integration and stable Action usage. +- [Copy-ready stable v1 consumer](../examples/github-action-consumer-v1.yml) — least-privilege example with explicit custody pins and independent test-success gating. +- [Current vs historical examples](../examples/README.md) — use v1 for new projects; preserve Alpha fixtures only for replay. - [Troubleshooting](TROUBLESHOOTING.md) — environment, ptrace and evidence-health diagnostics. - [Examples](EXAMPLES.md) — command-line usage examples. - [Why provenance is not the same as runtime behavioral integrity](WHY_RUNTIME_BEHAVIORAL_INTEGRITY.md) — shareable technical explanation of the problem ExecSurface addresses. @@ -62,6 +64,6 @@ When documents from different dates appear to conflict, use this order for curre 4. the latest release-specific document under `docs/releases/`; 5. dated milestone/development/archive records for chronology and historical evidence only. -ExecSurface Alpha.5 remains bounded to Linux x86_64. ARM64 is not claimed. Native ptrace remains the bounded public reference observer. Independent external validation is not claimed unless qualified external evidence is explicitly recorded. +ExecSurface **v1.0.0** is the supported stable release for Linux x86_64 with native ptrace as the bounded public observer. Alpha.5/Alpha.6 are immutable historical releases, not recommended for new onboarding. ARM64 and independent external validation are not claimed without corresponding evidence. Security-sensitive findings must follow [`SECURITY.md`](../SECURITY.md) rather than public evidence channels. diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 00000000..b3bf2f09 --- /dev/null +++ b/examples/README.md @@ -0,0 +1,26 @@ +# ExecSurface examples — current v1 first + +**For new users, use stable ExecSurface v1.0.0, not the historical Alpha tags.** + +| Path | Status | Recommended use | +| --- | --- | --- | +| [Stable v1 GitHub Action consumer](github-action-consumer-v1.yml) | **Current v1** (`AETHERXGLOBAL/execsurface@v1`) | Copy-ready Rust CI integration after explicit baseline and policy custody setup | +| [Five-Minute Start](../docs/QUICKSTART_5_MIN.md) | **Current v1** | Test the published v1 binary against controlled PASS/REVIEW scenarios | +| [Python/pytest PASS→REVIEW](python-pytest/README.md) | **Historical Alpha.5** | Replay preserved third-party contributed evidence only; not v1 onboarding | +| [Minimal controlled drift](hello-drift.sh) | Check selected release/CLI contract | Small local demonstration | + +## Supported stable release + +- GitHub Release: https://github.com/AETHERXGLOBAL/execsurface/releases/tag/v1.0.0 +- Stable Action: `AETHERXGLOBAL/execsurface@v1` +- Immutable Action: `AETHERXGLOBAL/execsurface@v1.0.0` +- Linux x86_64 with native `ptrace`; see [current status](../docs/STATUS.md). +- A PASS is an execution-surface drift result, **not** proof that the target command exited successfully. Keep the native test/build step independent. + +## Historical evidence is not a current default + +The Python/pytest recipe contributed through [PR #128](https://github.com/AETHERXGLOBAL/execsurface/pull/128) by @astrogilda deliberately preserves the immutable Alpha.5 binary pin, original receipts, and negative nondeterminism evidence. It was **not** relabeled as a v1 test or independently certified for v1. The historical example remains discoverable for exact replay; new installations and workflows should use the v1 links above. + +The stable v1 copy-ready GitHub Action workflow builds on the original external example direction proposed by @PandaHUN777 in [PR #127](https://github.com/AETHERXGLOBAL/execsurface/pull/127), with added v1 target-success gating, external custody pins and a copy-safe documentation link. + +No Alpha result or external community comment should be represented as independent v1 adoption. diff --git a/examples/github-action-consumer-v1.yml b/examples/github-action-consumer-v1.yml new file mode 100644 index 00000000..5fa27184 --- /dev/null +++ b/examples/github-action-consumer-v1.yml @@ -0,0 +1,62 @@ +# Copy to .github/workflows/execsurface.yml in a Rust consumer repository. +# CURRENT SUPPORTED CHANNEL: AETHERXGLOBAL/execsurface@v1 (stable v1.x). +# For an immutable version review, substitute @v1.0.0. +# Docs: https://github.com/AETHERXGLOBAL/execsurface/blob/main/docs/GITHUB_ACTION.md +# +# Before enabling: +# 1. Install and verify ExecSurface v1.0.0 (see the v1 quickstart). +# 2. Review/create execsurface-policy.json and learn execsurface.lock.json +# using exactly: execsurface learn --output execsurface.lock.json -- /bin/bash -lc 'cargo test --locked' +# on a comparable Linux x86_64 environment. Review and commit both files. +# 3. Set GitHub repository variables EXECSURFACE_BASELINE_DIGEST (from the +# reviewed baseline's baseline_digest) and EXECSURFACE_POLICY_SHA256 +# ("sha256:" + SHA-256 of the *exact* reviewed policy bytes). +# Set these only from a trusted maintainer context, never from PR content. +# 4. The first CI check may legitimately produce REVIEW when build/runner +# behavior differs from the environment whose baseline was approved. +# Investigate the difference; do not automatically relearn. +# +# NOTE: Stable-v1 ExecSurface PASS is a drift verdict, not proof that the +# wrapped test command succeeded. The independent test step below is essential. +name: ExecSurface v1 — Rust consumer +on: + pull_request: + +permissions: + contents: read + +jobs: + runtime-drift: + runs-on: ubuntu-24.04 + steps: + - name: Check out code without persisting credentials + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + + - name: Verify native test outcome independently + run: cargo test --locked + + - name: Check approved execution surface with ExecSurface v1 + id: execsurface + uses: AETHERXGLOBAL/execsurface@v1 + with: + command: "cargo test --locked" + baseline: execsurface.lock.json + policy: execsurface-policy.json + expected-baseline-digest: ${{ vars.EXECSURFACE_BASELINE_DIGEST }} + expected-policy-sha256: ${{ vars.EXECSURFACE_POLICY_SHA256 }} + require-custody: "true" + fail-on-review: "true" + # Evidence can contain filesystem/network metadata: inspect before sharing. + upload-artifact: "false" + + - name: Assert the explicit ExecSurface verdict + if: success() + shell: bash + env: + VERDICT: ${{ steps.execsurface.outputs.verdict }} + VERDICT_EXIT: ${{ steps.execsurface.outputs.exit-code }} + run: | + test "$VERDICT" = "pass" + test "$VERDICT_EXIT" = "0"