diff --git a/.github/scripts/validate-a2ml.sh b/.github/scripts/validate-a2ml.sh index 5019542..5c0cab5 100755 --- a/.github/scripts/validate-a2ml.sh +++ b/.github/scripts/validate-a2ml.sh @@ -2,6 +2,13 @@ # SPDX-License-Identifier: PMPL-1.0-or-later # Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) # +# Vendored from hyperpolymath/a2ml-validate-action @ 86c6da6 (#8), with one +# repair: upstream had a stray newline splitting a comment ("# own \name/...") +# so `ame/project` ran as a command and aborted the script under `set -e`. +# The action SHA this repo previously pinned predated the typed-manifest / +# contractile-shape identity exemptions. Re-adopt the upstream action once +# its HEAD is fixed. +# # validate-a2ml.sh — A2ML manifest validation script # # Scans for .a2ml files and validates: @@ -127,14 +134,12 @@ validate_a2ml() { while IFS= read -r line; do line_num=$((line_num + 1)) - # Check for identity fields (various A2ML patterns). Accept TOML - # (`key = …`) and YAML-flavoured (`key: …`) forms, and the - # canonical-/prefixed-name + id keys used by clade/anchor docs. - if [[ "$line" =~ ^[[:space:]]*(agent[-_]id|name|project|id|canonical-name|prefixed-name)[[:space:]]*[=:] ]]; then + # Check for identity fields (various A2ML patterns) + if [[ "$line" =~ ^[[:space:]]*(agent[-_]id|name|project)[[:space:]]*= ]]; then has_identity=true fi - # Check for version field (TOML or YAML form) - if [[ "$line" =~ ^[[:space:]]*(version|schema_version)[[:space:]]*[=:] ]]; then + # Check for version field + if [[ "$line" =~ ^[[:space:]]*(version|schema_version)[[:space:]]*= ]]; then has_version=true fi done < "$file" @@ -162,15 +167,6 @@ validate_a2ml() { ;; esac - # Path-identified instruction docs under .machine_readable/agent_instructions/ - # (coverage/debt/methodology…) derive identity from directory + filename, - # like the 6a2 typed manifests, and carry only a [metadata] version block. - case "$file" in - */.machine_readable/agent_instructions/*.a2ml) - is_manifest=true - ;; - esac - # Contractile-shape A2ML files use `@directive:` syntax instead of # TOML `key = value`. Trustfile.a2ml, Intentfile.a2ml, Mustfile.a2ml, # Adjustfile.a2ml etc. are policy / trust / intent / abstract files diff --git a/.github/workflows/dogfood-gate.yml b/.github/workflows/dogfood-gate.yml index 027311f..91a714d 100644 --- a/.github/workflows/dogfood-gate.yml +++ b/.github/workflows/dogfood-gate.yml @@ -45,16 +45,16 @@ jobs: # recognises the clade/anchor/agent-instruction identity shapes. - name: Validate A2ML manifests if: steps.detect.outputs.count > 0 - uses: hyperpolymath/a2ml-validate-action@fd7b2d840449568867f88cc93f64a9b3db1e2153 # contractile-shape carve-out (#9) - with: - path: '.' - strict: 'false' - # Defaults (pinned action fd7b2d8 has no built-in default for this - # input) plus two files that declare their identity in a non-TOML - # A2ML dialect the pinned validator's `key =` regex cannot see: - # ANCHOR.a2ml uses `id: "..."` and Bustfile.a2ml a curly block - # with `name: "..."`. They are valid, just a different doc shape. - paths-ignore: | + shell: bash + env: + INPUT_PATH: '.' + INPUT_STRICT: 'false' + # Default carve-outs plus stapeln's legitimately distinct A2ML + # doc-types whose identity is structural, not a TOML name/version + # pair: clade declarations, YAML anchor files, and agent-instruction + # session configs. Same rationale as the action's built-in defaults + # (hyperpolymath/hypatia#243 — distinguish doc type from target). + INPUT_PATHS_IGNORE: | vendor/ vendored/ verified-container-spec/ @@ -62,8 +62,10 @@ jobs: integration/fixtures/ test/fixtures/ tests/fixtures/ - anchors/ANCHOR.a2ml - contractiles/bust/Bustfile.a2ml + .machine_readable/agent_instructions/ + .machine_readable/CLADE.a2ml + .machine_readable/anchors/ + run: .github/scripts/validate-a2ml.sh - name: Write summary run: | diff --git a/.github/workflows/hypatia-scan.yml b/.github/workflows/hypatia-scan.yml index b1eb151..00453be 100644 --- a/.github/workflows/hypatia-scan.yml +++ b/.github/workflows/hypatia-scan.yml @@ -45,8 +45,12 @@ jobs: continue-on-error: true uses: erlef/setup-beam@fc68ffb90438ef2936bbb3251622353b3dcb2f93 # v1.18.2 with: - elixir-version: '1.19.4' - otp-version: '28.3' + # Hypatia's mix.exs requires `elixir ~> 1.14`. The previous pins + # (Elixir 1.19.4 / OTP 28.3) are not in setup-beam's version index, + # so the step failed in ~15s before any scan ran. Use known-good + # stable lines; major.minor lets setup-beam pick the latest patch. + elixir-version: '1.17' + otp-version: '27' - name: Clone Hypatia continue-on-error: true @@ -59,12 +63,13 @@ jobs: continue-on-error: true working-directory: ${{ env.HOME }}/hypatia run: | - if [ ! -f hypatia-v2 ]; then - echo "Building hypatia-v2 scanner..." - cd scanner + # The Hypatia mix project lives at the repo root (there is no + # scanner/ subdirectory). escript.build emits ./hypatia, which + # hypatia-cli.sh prefers (hypatia-v2 is only a legacy fallback). + if [ ! -x hypatia ] && [ ! -x hypatia-v2 ]; then + echo "Building hypatia escript..." mix deps.get mix escript.build - mv hypatia ../hypatia-v2 fi # No explicit build step: hypatia-cli.sh self-builds the escript diff --git a/.github/workflows/secret-scanner.yml b/.github/workflows/secret-scanner.yml index 8fb3ead..544c7fe 100644 --- a/.github/workflows/secret-scanner.yml +++ b/.github/workflows/secret-scanner.yml @@ -18,22 +18,18 @@ jobs: with: fetch-depth: 0 # Full history for scanning - # The trufflehog GitHub Action runs in git-diff mode and exits non-zero - # with "BASE and HEAD commits are the same" on several event shapes - # (fresh branch push, single-commit PR), failing the job even when no - # secret exists. Invoke the pinned CLI directly for a deterministic - # full-history scan that only fails on a *verified* finding. - - name: TruffleHog Secret Scan - uses: trufflesecurity/trufflehog@37b77001d0174ebec2fcca2bd83ff83a6d45a3ab # v3.95.3 - with: - # Scan the full checked-out history (fetch-depth: 0 above) rather - # than an event-derived base..head range. The old pin failed every - # run with "BASE and HEAD commits are the same" on push-to-main and - # on PRs (empty/degenerate diff range) — a wrapper bug, not a real - # finding (a full-tree scan reports zero secrets). An empty `base` - # makes the scan deterministic and only fails on verified secrets. - base: "" - extra_args: --only-verified + # The trufflehog GitHub Action wraps a Docker range-scan + # (--since-commit BASE --branch HEAD against :latest) that fails on PRs + # even when there are zero secrets. A full-history filesystem scan is + # deterministic and is the mode actually intended here. Version pinned + # for reproducibility. + - name: Install TruffleHog + run: | + curl -sSfL https://raw.githubusercontent.com/trufflesecurity/trufflehog/main/scripts/install.sh \ + | sh -s -- -b /usr/local/bin v3.95.3 + + - name: TruffleHog Secret Scan (full history) + run: trufflehog git "file://$GITHUB_WORKSPACE" --only-verified --fail --no-update gitleaks: runs-on: ubuntu-latest diff --git a/container-stack/vordr/Containerfile b/container-stack/vordr/Containerfile index eaaf921..e648901 100644 --- a/container-stack/vordr/Containerfile +++ b/container-stack/vordr/Containerfile @@ -7,7 +7,10 @@ # artefacts and are NOT shipped in the container image. # ── Stage 1: Build ──────────────────────────────────────────────── -FROM rust:1.83-slim AS rust-builder +# Rust >= 1.86 is required: the pinned Cargo.lock resolves icu_* 2.2.0 / +# idna_adapter 1.2.2 (MSRV 1.86) and indexmap 2.14.0 (Cargo edition2024, +# needs Cargo >= 1.85). Older toolchains fail at manifest parse time. +FROM rust:1.86-slim AS rust-builder RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config libsqlite3-dev ca-certificates \