From 495ebc0ad65ef374f0b2782f6c99f379f8672a31 Mon Sep 17 00:00:00 2001 From: //AM Date: Mon, 24 Aug 2026 14:34:31 -0400 Subject: [PATCH 1/3] Align AuthContract with SDLC v1.2 surfaces Adds bounded security, versioning, dependency, falsification, SBOM, and agent-observability controls without changing product semantics. NOT SELF-ADJUDICATED Agent-Assisted-By: OpenAI Codex (GPT-5) Veraxis-Skill: SDLC-v1.2-alignment --- .github/workflows/authcontract-gate.yml | 4 +- .github/workflows/ci.yml | 6 +- .github/workflows/security.yml | 32 +++++++++ .gitignore | 2 + AGENTS.md | 14 ++++ CONTRIBUTING.md | 30 ++++++++ DEPENDENCIES.md | 24 +++++++ Makefile | 18 +++++ README.md | 12 ++-- SECURITY.md | 48 +++++++++++++ VERSIONING.md | 46 ++++++++++++ docs/AGENT-OBSERVABILITY.md | 46 ++++++++++++ docs/SDLC-V1.2-STATUS.md | 25 +++++++ pyproject.toml | 4 +- scripts/falsify.py | 95 +++++++++++++++++++++++++ scripts/generate_sbom.py | 50 +++++++++++++ scripts/no_network/sitecustomize.py | 15 ++++ scripts/verify_no_network.py | 39 ++++++++++ 18 files changed, 499 insertions(+), 11 deletions(-) create mode 100644 .github/workflows/security.yml create mode 100644 CONTRIBUTING.md create mode 100644 DEPENDENCIES.md create mode 100644 Makefile create mode 100644 SECURITY.md create mode 100644 VERSIONING.md create mode 100644 docs/AGENT-OBSERVABILITY.md create mode 100644 docs/SDLC-V1.2-STATUS.md create mode 100644 scripts/falsify.py create mode 100644 scripts/generate_sbom.py create mode 100644 scripts/no_network/sitecustomize.py create mode 100644 scripts/verify_no_network.py diff --git a/.github/workflows/authcontract-gate.yml b/.github/workflows/authcontract-gate.yml index 78730f1..d47cd78 100644 --- a/.github/workflows/authcontract-gate.yml +++ b/.github/workflows/authcontract-gate.yml @@ -19,7 +19,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout PR test-merge composition - uses: actions/checkout@v4 + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 with: # Default ref for a pull_request-triggered workflow is GitHub's # own ephemeral merge commit (refs/pull//merge, i.e. @@ -32,7 +32,7 @@ jobs: - name: Fetch current base run: git fetch origin "${{ github.event.pull_request.base.ref }}" - - uses: actions/setup-python@v5 + - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: python-version: "3.12" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 08c5342..de47599 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,9 +11,9 @@ jobs: matrix: python-version: ["3.10", "3.12"] steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 + - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: python-version: ${{ matrix.python-version }} - run: pip install -e ".[test]" - - run: pytest -q + - run: make ci diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml new file mode 100644 index 0000000..2df6b38 --- /dev/null +++ b/.github/workflows/security.yml @@ -0,0 +1,32 @@ +name: Dependency and vulnerability review + +on: + pull_request: + push: + branches: [main] + +permissions: + contents: read + +jobs: + dependency-review: + if: github.event_name == 'pull_request' + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: read + steps: + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 + - uses: actions/dependency-review-action@2031cfc080254a8a887f58cffee85186f0e49e48 # v4.9.0 + + advisory-scan: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 + - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 + with: + python-version: "3.12" + - run: python -m pip install --upgrade "pip>=26.2" "pip-audit==2.10.1" + - run: python -m pip install -e ".[test]" + - run: python -m pip_audit --skip-editable + - run: make sbom diff --git a/.gitignore b/.gitignore index 4e33d94..29743a4 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ __pycache__/ *.pyc *.egg-info/ .pytest_cache/ +.venv/ +build/ diff --git a/AGENTS.md b/AGENTS.md index 9dc7687..ca1f3bd 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -60,6 +60,20 @@ Verify: `pytest -q` → `342 passed`. **Not on PyPI.** `pip install authcontract` will not work. Install from source only. +## 4.1 Real repository skills + +Agents may use only these implemented workflows: + +- `make test` — execute the committed test suite; +- `make falsify` — exercise the bounded PASS/refusal/tamper cases; +- `make no-network` — run the local install/import/test/CLI network guard; +- `make sbom` — generate the bounded candidate SBOM; and +- the six CLI commands listed below. + +None of these commands publishes, deploys, attests a release, or adjudicates its +own result. Producers must state `NOT SELF-ADJUDICATED` and stop for independent +verification. + ## 5. Supported CLI commands Exactly six. Any other subcommand does not exist. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..c08c010 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,30 @@ +# Contributing + +AuthContract is an experimental evidence repository with no general acceptance +promise. Start with a GitHub issue describing the bounded problem, the exact +commit SHA, and a reproducer against synthetic fixtures. This is the reliable +path for bugs, claim corrections, and proposed changes. + +For a code contribution: + +1. agree scope with the owner before substantial work; +2. create a focused branch and pull request—never push directly to `main`; +3. run `make ci` and include the literal output and commit SHA; +4. state the producer and proposed independent verifier; +5. label claims as proved, measured, argued, or assumed; and +6. state `NOT SELF-ADJUDICATED` in the pull request. + +AI-assisted contributions should add these trailers when applicable: + +```text +Agent-Assisted-By: +Veraxis-Skill: +Agent-Execution-ID: +``` + +Trailers are supplemental provenance. They do not establish authorship, +authority, independent verification, or acceptance. Security reports follow +`SECURITY.md`, not the public issue path. + +No contributor licence agreement or licence grant is established by this file. + diff --git a/DEPENDENCIES.md b/DEPENDENCIES.md new file mode 100644 index 0000000..c29e202 --- /dev/null +++ b/DEPENDENCIES.md @@ -0,0 +1,24 @@ +# Dependency policy + +AuthContract has one runtime dependency: `rfc8785`, which supplies the JSON +Canonicalization Scheme used in identity-bearing digests. Because a +canonicalization change can change artifact identity, the supported range is +bounded to the audited `0.1` line: `>=0.1.2,<0.2`. + +The test extra bounds pytest to `>=7,<10`. Build tooling is declared separately +in `pyproject.toml`; it is not a runtime dependency. + +This repository uses ranges for compatibility testing rather than claiming a +single universal lock across Python 3.10 and 3.12. Evidence must record the +resolved environment for the exact run. Pull requests receive dependency-diff +review and an advisory scan through `.github/workflows/security.yml`. +The scan upgrades its own `pip` environment before auditing and skips the local +editable AuthContract package, which is not a published PyPI dependency. + +`make sbom` records the installed AuthContract and runtime dependency versions +in a deterministic CycloneDX document for the current candidate. It does not +attest a release, include operating-system packages, or establish that a +dependency is vulnerability-free. + +Dependency updates that could affect canonical bytes, digests, exit behavior, +or receipt verification require the positive and negative verification suite. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..195edb1 --- /dev/null +++ b/Makefile @@ -0,0 +1,18 @@ +.PHONY: test falsify no-network sbom ci + +PYTHON ?= python3 + +test: + $(PYTHON) -m pytest -q + +falsify: + $(PYTHON) scripts/falsify.py + +no-network: + $(PYTHON) scripts/verify_no_network.py + +sbom: + $(PYTHON) scripts/generate_sbom.py --output build/authcontract.cdx.json + +ci: test falsify no-network sbom + diff --git a/README.md b/README.md index f9d7b47..1a6eaad 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,8 @@ pip install -e ".[test]" Confirm the install: ```bash -pytest -q # expect: 342 passed +make test # expect: 342 passed +make falsify # expect: 4/4 bounded outcomes observed ``` > Not on PyPI. Install from source, as above. @@ -264,6 +265,9 @@ Measured evidence and its limits: [`docs/BENCHMARKS.md`](docs/BENCHMARKS.md) · | See how this repository was usability-tested | [`docs/REPOSITORY-USABILITY.md`](docs/REPOSITORY-USABILITY.md) | | See the release-readiness verification record | [`docs/RELEASE-READINESS.md`](docs/RELEASE-READINESS.md) | | Understand the terminology | [`docs/DEVELOPER-LANGUAGE.md`](docs/DEVELOPER-LANGUAGE.md) | +| Review dependency and SBOM policy | [`DEPENDENCIES.md`](DEPENDENCIES.md) | +| Review security reporting | [`SECURITY.md`](SECURITY.md) | +| Review compatibility policy | [`VERSIONING.md`](VERSIONING.md) | | See how this compares to other systems | [`docs/SOTA.md`](docs/SOTA.md) | | Understand the full conceptual model | keep reading below | | Use AuthContract from an AI coding agent | [`AGENTS.md`](AGENTS.md) | @@ -279,9 +283,9 @@ Measured evidence and its limits: [`docs/BENCHMARKS.md`](docs/BENCHMARKS.md) · | **Commercial or institutional use** | [veraxis.io](https://veraxis.io) | **Contributions.** There is no contribution process established yet, and no -contributor licence or review policy exists. Issues are the reliable path today. -If you are considering a substantive contribution, open an issue first so it -isn't wasted effort. +contributor licence or acceptance promise. Issues remain the starting point; +the exact branch, evidence, role-separation, and agent-provenance expectations +are in [`CONTRIBUTING.md`](CONTRIBUTING.md). **A note on scope of support.** This is an experimental reference implementation maintained as research and engineering evidence. There is no support commitment, diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..f5d4405 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,48 @@ +# Security policy + +AuthContract is an experimental, pre-1.0 reference implementation. It is not a +production security control, certification system, or substitute for an +institution's authorization controls. + +## Supported versions + +Only the current `main` commit is maintained. No released or long-term-support +version exists. Reports against older commits are still useful when they show a +design or integrity defect that remains present on `main`. + +## Private reporting + +Do not open a public issue for an undisclosed vulnerability. Use GitHub's +[private vulnerability report](https://github.com/veraxis-protocol/AuthContract/security/advisories/new) +for this repository. Include the affected commit SHA, a minimal reproducer, +impact, and whether the issue can expose or wrongly authorize a consequential +action. If the private-report form is unavailable to your account, contact the +repository owner privately through the contact route published at +[veraxis.io](https://veraxis.io/) before disclosing details. + +Never include credentials, production policy, personal data, or live +institutional evidence in a report. Use synthetic fixtures. + +## Scope and triage + +High-priority reports include: + +- acceptance of a digest-, artifact-, action-, fact-, or receipt-tamper; +- fail-open behavior on malformed, missing, stale, or inadmissible inputs; +- mismatch between the action checked and the action represented in a receipt; +- dependency or build compromise affecting the tested package; and +- a claim in the repository that materially exceeds the measured behavior. + +The owner will acknowledge receipt when practical, reproduce against an exact +commit, record whether the report is confirmed, and coordinate disclosure after +a fix or bounded explanation is available. No response-time or remediation-time +commitment is established. Reports are evidence, not authorization to publish, +deploy, or change production systems. + +## Out of scope + +The repository has no service, hosted endpoint, persistence layer, production +identity system, or telemetry backend. Reports that assume those nonexistent +surfaces are not applicable. Automated natural-language source-to-rule +comparison is also not implemented end to end. + diff --git a/VERSIONING.md b/VERSIONING.md new file mode 100644 index 0000000..e173d48 --- /dev/null +++ b/VERSIONING.md @@ -0,0 +1,46 @@ +# Versioning and compatibility + +AuthContract is currently version `0.0.1`: experimental and pre-1.0. The +repository has no published package or release compatibility promise. Pin an +exact commit SHA when reproducing or integrating it. + +## Versioned surfaces + +The following are public integration surfaces at a pinned commit, but may +change incompatibly before 1.0: + +- the six CLI subcommands and their flags; +- exit codes (`0` for PASS/ALLOW, `1` for refusal or error); +- JSON `status`, `decision`, and `reason_code` values; +- the Python functions and result objects documented in `AGENTS.md`; +- contract artifact, runtime-fact, action, and receipt JSON structures; and +- canonicalization and digest rules used to bind those structures. + +Human-readable messages are never a compatibility interface. Consumers should +branch on structured fields, while still pinning the exact commit because the +reason-code set is not yet frozen. + +## Change rules + +Before 1.0, a change to a CLI name or flag, exit semantics, reason code, Python +signature, required JSON field, canonicalization rule, or digest scope is a +breaking change. Such a change must: + +1. be explicit in the pull request and documentation; +2. update positive and negative fixtures and tests; +3. identify affected receipts and artifacts; +4. avoid silently reinterpreting an existing digest; and +5. use a new artifact/schema/version identity when old and new bytes could + otherwise be confused. + +Adding an optional field is compatible only when older consumers safely ignore +it and its presence cannot widen authority. A new refusal condition is treated +as behaviorally consequential even when it fails closed. + +## Releases and artifacts + +No distributable release or attestation is established. Source installs are the +only supported installation route. An SBOM may be generated for a candidate +commit with `make sbom`; it is evidence about resolved package metadata, not a +release attestation or security guarantee. + diff --git a/docs/AGENT-OBSERVABILITY.md b/docs/AGENT-OBSERVABILITY.md new file mode 100644 index 0000000..c7d832e --- /dev/null +++ b/docs/AGENT-OBSERVABILITY.md @@ -0,0 +1,46 @@ +# Agent observability and provenance + +AuthContract has no telemetry client, analytics endpoint, hosted agent gateway, +or MCP server. Local reads and reasoning are dark unless a contributor records +them; this repository must not imply otherwise. + +## Observable events + +GitHub can attribute commits, pull requests, reviews, comments, checks, and +workflow runs to the authenticated GitHub actor. Those events establish +transport attribution only. They do not prove that an actor held institutional +authority, that a model performed the work claimed, or that a review was +independent. + +Contributors may add commit trailers: + +```text +Agent-Assisted-By: +Veraxis-Skill: +Agent-Execution-ID: +``` + +Trailers are supplemental provenance, not authorization or adjudication. +Producer, verifier, and adjudicator must remain distinct. + +## Dark local activity + +File reads, prompts, local model reasoning, and commands outside an attributable +system are not observable from Git history. Do not reconstruct or claim those +events without literal evidence. A missing trailer does not prove that no agent +was used; a trailer does not prove the described execution occurred. + +## No outbound analytics + +Run `make no-network` to install the local project without an index and exercise +package import, the full tests, and a CLI command with Python socket connections +blocked. A PASS is bounded to the exercised Python processes at the tested +commit. It does not inspect operating-system traffic from unrelated tools or +prove facts about a future binary. + +## Unimplemented remote surfaces + +A hosted AuthContract verifier, Veraxis gateway, remote context service, and MCP +server are **NOT IMPLEMENTED** in this repository. No URL, execution identifier, +or remote-observability claim should be invented for them. + diff --git a/docs/SDLC-V1.2-STATUS.md b/docs/SDLC-V1.2-STATUS.md new file mode 100644 index 0000000..b46b6f7 --- /dev/null +++ b/docs/SDLC-V1.2-STATUS.md @@ -0,0 +1,25 @@ +# SDLC v1.2 disposition + +Baseline: `ce783851897b8ddbbe92fae2b098b8bee8e88f57`. + +This producer record reports literal repository evidence. It does not accept its +own claims and is **NOT SELF-ADJUDICATED**. The governing `CURRENT-SDLC.md` v1.2 +text was not present in this repository at the baseline, so gate names are not +reconstructed from memory; the IDs and evidence disposition are recorded +without inventing missing normative text. + +| Gate | Disposition | Literal evidence / limitation | +|---|---|---| +| E | PASS | Clean source install and full test suite are exercised by `make test` and `make no-network`. | +| F | PASS | `make falsify` checks valid PASS plus unclassified-action, stale-fact, and receipt-tamper refusals. | +| G | PASS | `SECURITY.md` defines supported scope, private reporting, and bounded triage. | +| H | PASS | Dependency review and vulnerability scanning are defined in `.github/workflows/security.yml`; `make sbom` generates a bounded SBOM. | +| I | PASS | `VERSIONING.md` identifies provisional CLI, Python, reason-code, artifact, and receipt contracts. | +| J | PASS | `README.md`, `AGENTS.md`, and `CONTRIBUTING.md` state the source-only, pre-1.0, no-license contribution boundary. | +| K | N/A | No distributable release is authorized; no release attestation is claimed. | +| L | NOT ESTABLISHED | Independent verification and adjudication have not occurred for this producer branch. | +| M | PASS | `docs/AGENT-OBSERVABILITY.md` distinguishes GitHub attribution from dark local work, defines trailers, and documents the no-network check. Remote gateway/MCP surfaces remain not implemented. | + +These dispositions must be checked against the authoritative `CURRENT-SDLC.md` +v1.2 by an independent verifier before adjudication. + diff --git a/pyproject.toml b/pyproject.toml index d80c1bc..c448ac3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,13 +3,13 @@ name = "authcontract" version = "0.0.1" description = "AuthContract reference implementation — canonical digest and runtime fact admissibility" requires-python = ">=3.10" -dependencies = ["rfc8785>=0.1.2"] +dependencies = ["rfc8785>=0.1.2,<0.2"] [project.scripts] authcontract = "authcontract.cli:main" [project.optional-dependencies] -test = ["pytest>=7.0"] +test = ["pytest>=7.0,<10"] [tool.setuptools.packages.find] include = ["authcontract*"] diff --git a/scripts/falsify.py b/scripts/falsify.py new file mode 100644 index 0000000..bbf96a8 --- /dev/null +++ b/scripts/falsify.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python3 +"""Run the bounded public AuthContract falsification cases.""" + +from __future__ import annotations + +import json +import subprocess +import sys +import tempfile +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[1] + + +def run_case(name: str, args: list[str], exit_code: int, status: str, reason: str) -> None: + result = subprocess.run( + [sys.executable, "-m", "authcontract", *args], + cwd=ROOT, + text=True, + capture_output=True, + check=False, + ) + try: + payload = json.loads(result.stdout) + except json.JSONDecodeError as exc: + raise AssertionError(f"{name}: stdout was not JSON: {result.stdout!r}") from exc + actual = (result.returncode, payload.get("status"), payload.get("reason_code")) + expected = (exit_code, status, reason) + if actual != expected: + raise AssertionError(f"{name}: expected {expected!r}, got {actual!r}; stderr={result.stderr!r}") + print(f"PASS {name}: exit={exit_code} status={status} reason_code={reason}") + + +def main() -> int: + artifact = "fixtures/banking_payment_specimen.json" + valid_action = "fixtures/actions/send_payment_valid.json" + valid_facts = "fixtures/runtime/facts_valid.json" + + run_case( + "valid decision", + ["run-specimen", artifact, valid_action, valid_facts, "--execution-result", "SIMULATED_SUCCESS"], + 0, + "PASS", + "OK", + ) + run_case( + "unclassified-action refusal", + [ + "run-specimen", + artifact, + "fixtures/actions/send_payment_unknown_action_type.json", + valid_facts, + "--execution-result", + "SIMULATED_SUCCESS", + ], + 1, + "REFUSED", + "RUN_UNCLASSIFIED_ACTION", + ) + run_case( + "stale-fact refusal", + [ + "run-specimen", + artifact, + valid_action, + "fixtures/runtime/facts_stale.json", + "--execution-result", + "SIMULATED_SUCCESS", + ], + 1, + "REFUSED", + "RUN_FACT_STALE", + ) + + receipt = json.loads((ROOT / "fixtures/runtime/receipt_valid.json").read_text()) + receipt["decision"] = "REFUSE" + with tempfile.TemporaryDirectory(prefix="authcontract-falsify-") as temp_dir: + tampered = Path(temp_dir) / "receipt-tampered.json" + tampered.write_text(json.dumps(receipt), encoding="utf-8") + run_case( + "receipt-tamper refusal", + ["verify-receipt", str(tampered), artifact, valid_action, valid_facts], + 1, + "REFUSED", + "VEIP_RECEIPT_MISMATCH", + ) + + print("PASS bounded falsification harness: 4/4 expected outcomes observed") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) + diff --git a/scripts/generate_sbom.py b/scripts/generate_sbom.py new file mode 100644 index 0000000..4c9473d --- /dev/null +++ b/scripts/generate_sbom.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python3 +"""Generate a deterministic, bounded CycloneDX SBOM from installed metadata.""" + +from __future__ import annotations + +import argparse +import hashlib +import importlib.metadata +import json +from pathlib import Path + + +def component(name: str) -> dict[str, object]: + distribution = importlib.metadata.distribution(name) + canonical = distribution.metadata["Name"] or name + version = distribution.version + return { + "type": "library", + "bom-ref": f"pkg:pypi/{canonical.lower()}@{version}", + "name": canonical, + "version": version, + "purl": f"pkg:pypi/{canonical.lower()}@{version}", + } + + +def main() -> int: + parser = argparse.ArgumentParser() + parser.add_argument("--output", type=Path, required=True) + args = parser.parse_args() + + components = sorted([component("authcontract"), component("rfc8785")], key=lambda item: str(item["name"])) + serial_material = json.dumps(components, sort_keys=True, separators=(",", ":")).encode() + serial = hashlib.sha256(serial_material).hexdigest() + document = { + "bomFormat": "CycloneDX", + "specVersion": "1.5", + "serialNumber": f"urn:uuid:{serial[:8]}-{serial[8:12]}-{serial[12:16]}-{serial[16:20]}-{serial[20:32]}", + "version": 1, + "metadata": {"component": next(item for item in components if item["name"] == "authcontract")}, + "components": components, + } + args.output.parent.mkdir(parents=True, exist_ok=True) + args.output.write_text(json.dumps(document, indent=2, sort_keys=True) + "\n", encoding="utf-8") + print(f"wrote {args.output} with {len(components)} components") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) + diff --git a/scripts/no_network/sitecustomize.py b/scripts/no_network/sitecustomize.py new file mode 100644 index 0000000..dbb35cb --- /dev/null +++ b/scripts/no_network/sitecustomize.py @@ -0,0 +1,15 @@ +"""Fail closed if Python code attempts an outbound socket connection.""" + +from __future__ import annotations + +import socket + + +def _blocked(*_args: object, **_kwargs: object) -> None: + raise RuntimeError("outbound network disabled by AuthContract verification guard") + + +socket.create_connection = _blocked # type: ignore[assignment] +socket.socket.connect = _blocked # type: ignore[assignment] +socket.socket.connect_ex = _blocked # type: ignore[assignment] + diff --git a/scripts/verify_no_network.py b/scripts/verify_no_network.py new file mode 100644 index 0000000..8b6b091 --- /dev/null +++ b/scripts/verify_no_network.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 +"""Exercise install/import/tests/CLI with outbound Python sockets blocked.""" + +from __future__ import annotations + +import os +import subprocess +import sys +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[1] +GUARD = ROOT / "scripts/no_network" + + +def run(label: str, command: list[str]) -> None: + env = os.environ.copy() + env["PYTHONPATH"] = str(GUARD) + os.pathsep + env.get("PYTHONPATH", "") + result = subprocess.run(command, cwd=ROOT, env=env, check=False) + if result.returncode != 0: + raise SystemExit(f"FAIL {label}: exit {result.returncode}") + print(f"PASS {label}: no outbound Python socket used") + + +def main() -> int: + run( + "offline editable install", + [sys.executable, "-m", "pip", "install", "--no-index", "--no-deps", "--no-build-isolation", "-e", "."], + ) + run("package import", [sys.executable, "-c", "import authcontract"]) + run("test suite", [sys.executable, "-m", "pytest", "-q"]) + run("CLI", [sys.executable, "-m", "authcontract", "verify", "fixtures/valid.json"]) + print("PASS no-network guard: install/import/tests/CLI completed without outbound Python sockets") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) + From b11320559c8e8ad904fba1a755717f4e91134b59 Mon Sep 17 00:00:00 2001 From: //AM Date: Mon, 24 Aug 2026 15:09:32 -0400 Subject: [PATCH 2/3] ci: preload offline build backend --- .github/workflows/ci.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index de47599..52a984e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,5 +15,8 @@ jobs: - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: python-version: ${{ matrix.python-version }} - - run: pip install -e ".[test]" + # The no-network reinstall later in `make ci` must find the declared build backend + # locally. Python 3.12+ runner virtual environments do not guarantee setuptools. + - run: python -m pip install "setuptools>=61,<85" + - run: python -m pip install -e ".[test]" - run: make ci From 442f020dbcdd0009f8f383bc88589f23fbc75996 Mon Sep 17 00:00:00 2001 From: //AM Date: Mon, 24 Aug 2026 15:39:14 -0400 Subject: [PATCH 3/3] docs: reconcile canonical gates and Node 24 actions --- .github/workflows/authcontract-gate.yml | 4 +-- .github/workflows/ci.yml | 4 +-- .github/workflows/security.yml | 8 +++--- docs/SDLC-V1.2-STATUS.md | 37 ++++++++++++------------- 4 files changed, 26 insertions(+), 27 deletions(-) diff --git a/.github/workflows/authcontract-gate.yml b/.github/workflows/authcontract-gate.yml index d47cd78..4e2c08e 100644 --- a/.github/workflows/authcontract-gate.yml +++ b/.github/workflows/authcontract-gate.yml @@ -19,7 +19,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout PR test-merge composition - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: # Default ref for a pull_request-triggered workflow is GitHub's # own ephemeral merge commit (refs/pull//merge, i.e. @@ -32,7 +32,7 @@ jobs: - name: Fetch current base run: git fetch origin "${{ github.event.pull_request.base.ref }}" - - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version: "3.12" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 52a984e..85872c1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,8 +11,8 @@ jobs: matrix: python-version: ["3.10", "3.12"] steps: - - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 - - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version: ${{ matrix.python-version }} # The no-network reinstall later in `make ci` must find the declared build backend diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index 2df6b38..86240a3 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -16,14 +16,14 @@ jobs: contents: read pull-requests: read steps: - - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 - - uses: actions/dependency-review-action@2031cfc080254a8a887f58cffee85186f0e49e48 # v4.9.0 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5.0.0 advisory-scan: runs-on: ubuntu-latest steps: - - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 - - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version: "3.12" - run: python -m pip install --upgrade "pip>=26.2" "pip-audit==2.10.1" diff --git a/docs/SDLC-V1.2-STATUS.md b/docs/SDLC-V1.2-STATUS.md index b46b6f7..b88d9f0 100644 --- a/docs/SDLC-V1.2-STATUS.md +++ b/docs/SDLC-V1.2-STATUS.md @@ -1,25 +1,24 @@ -# SDLC v1.2 disposition +# SDLC v1.2 producer status Baseline: `ce783851897b8ddbbe92fae2b098b8bee8e88f57`. -This producer record reports literal repository evidence. It does not accept its -own claims and is **NOT SELF-ADJUDICATED**. The governing `CURRENT-SDLC.md` v1.2 -text was not present in this repository at the baseline, so gate names are not -reconstructed from memory; the IDs and evidence disposition are recorded -without inventing missing normative text. +This matrix uses the canonical public-release gate definitions in owner-authorized +`CURRENT-SDLC.md` v1.2. It reports literal producer evidence, does not accept its own +claims, and is **NOT SELF-ADJUDICATED**. -| Gate | Disposition | Literal evidence / limitation | -|---|---|---| -| E | PASS | Clean source install and full test suite are exercised by `make test` and `make no-network`. | -| F | PASS | `make falsify` checks valid PASS plus unclassified-action, stale-fact, and receipt-tamper refusals. | -| G | PASS | `SECURITY.md` defines supported scope, private reporting, and bounded triage. | -| H | PASS | Dependency review and vulnerability scanning are defined in `.github/workflows/security.yml`; `make sbom` generates a bounded SBOM. | -| I | PASS | `VERSIONING.md` identifies provisional CLI, Python, reason-code, artifact, and receipt contracts. | -| J | PASS | `README.md`, `AGENTS.md`, and `CONTRIBUTING.md` state the source-only, pre-1.0, no-license contribution boundary. | -| K | N/A | No distributable release is authorized; no release attestation is claimed. | -| L | NOT ESTABLISHED | Independent verification and adjudication have not occurred for this producer branch. | -| M | PASS | `docs/AGENT-OBSERVABILITY.md` distinguishes GitHub attribution from dark local work, defines trailers, and documents the no-network check. Remote gateway/MCP surfaces remain not implemented. | +| Gate | Canonical gate | Disposition | Literal evidence / limitation | +|---|---|---|---| +| E | Human Repository Usability | PASS | The README first screen states purpose and maturity and provides copy/paste clean-clone, install, meaningful valid/refusal CLI, expected output, integration, and boundary paths. `make ci` exercises the documented implementation. | +| F | Agent Usability | PASS | `AGENTS.md` gives real install, verification, falsification, CLI, evidence-reading, and boundary instructions without inventing interfaces. | +| G | Adoption Readiness | NOT ESTABLISHED | The README provides a truthful first-run and integration surface, but no adoption/conversion result is established; no star prompt or repository CTA is treated as adoption proof. | +| H | Supply-Chain & Release Integrity | PASS | Consequential Actions are immutable-SHA pinned; PR dependency review, advisory scanning, and SBOM generation run in CI. No package/release artifact is published, so artifact digest, provenance, and attestation are not applicable to the current source-only state and are not claimed. | +| I | Security & Vulnerability Management | PASS | `SECURITY.md` states supported scope, a private disclosure route, triage expectations, and scanner limits; dependency review and `pip-audit` are green on the exact PR head. A scanner result is not represented as an audit. | +| J | API & Versioning Integrity | PASS | `VERSIONING.md` declares the pre-1.0 Python API/import, CLI, exit, reason-code, artifact, receipt, and compatibility surfaces. | +| K | Machine-Readable Discovery & Licensing | NOT ESTABLISHED | `pyproject.toml` provides truthful package metadata, but the repository grants no license and declares no SPDX license identity. No grant is invented. | +| L | Public Falsification Completeness | PASS | `make falsify` publicly exercises one valid decision and three meaningful refusal/tamper paths: unclassified action, stale fact, and receipt mismatch (4/4). | +| M | Agent Interaction Observability | NOT ESTABLISHED | `docs/AGENT-OBSERVABILITY.md` truthfully documents GitHub-attributable versus dark local activity and the no-hidden-telemetry/no-network boundary. No approved ingestion pipeline, hosted gateway, or MCP observability implementation is established. | -These dispositions must be checked against the authoritative `CURRENT-SDLC.md` -v1.2 by an independent verifier before adjudication. +## Independent Adjudication +Independent Adjudication remains pending for the designated independent reviewer and owner. +GitHub CI success is evidence, not acceptance. **CI GREEN IS NOT ACCEPTANCE.**