diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..ec35fea --- /dev/null +++ b/.github/CODE_OF_CONDUCT.md @@ -0,0 +1,6 @@ + + +# Code of conduct + +See the project’s [Code of Conduct](../CODE_OF_CONDUCT.adoc) for participation +standards, reporting contacts and enforcement procedures. diff --git a/.github/SECURITY.md b/.github/SECURITY.md new file mode 100644 index 0000000..aa894f2 --- /dev/null +++ b/.github/SECURITY.md @@ -0,0 +1,7 @@ + + +# Security policy + +See [SECURITY.adoc](../SECURITY.adoc) for supported versions and private +vulnerability reporting. Do not report suspected vulnerabilities in public +issues. diff --git a/.github/workflows/proven-tests.yml b/.github/workflows/proven-tests.yml index d52eeb9..2d6cbac 100644 --- a/.github/workflows/proven-tests.yml +++ b/.github/workflows/proven-tests.yml @@ -181,7 +181,9 @@ jobs: - name: Install Idris2 (chez backend) working-directory: .proven-tests env: - IDRIS2_VERSION: ${{ env.IDRIS2_VERSION }} + # The pinned older installer passes this verbatim to git --branch. + # Idris2's release ref is v0.7.0, not 0.7.0. + IDRIS2_VERSION: v${{ env.IDRIS2_VERSION }} run: bash scripts/install-idris2.sh - name: Build and run the framework's suite diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index be1ea2b..91d0306 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -47,6 +47,29 @@ env: RUST_BACKTRACE: '1' jobs: + entrypoints: + name: Installation entrypoint controls + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - name: Verify pinned task runner and exercise isolated entrypoints + shell: bash + run: | + set -euo pipefail + tools_dir=$(mktemp -d) + trap 'rm -rf "$tools_dir"' EXIT + archive=just-1.36.0-x86_64-unknown-linux-musl.tar.gz + curl --fail --silent --show-error --location --max-time 60 \ + "https://github.com/casey/just/releases/download/1.36.0/$archive" \ + --output "$tools_dir/$archive" + (cd "$tools_dir" && printf '%s %s\n' \ + bc7c9f377944f8de9cd0418b11d2955adebfa25a488c0b5e3dd2d2c0e9d732da "$archive" | sha256sum --check) + tar --no-same-owner -xzf "$tools_dir/$archive" -C "$tools_dir" just + JUST_BIN="$tools_dir/just" bash scripts/ci/test-entrypoints.sh + fmt: name: cargo fmt --check runs-on: ubuntu-latest diff --git a/Justfile b/Justfile index 9975dec..f3a5ef4 100644 --- a/Justfile +++ b/Justfile @@ -8,7 +8,7 @@ default: build test # Build release binary build: - cargo build --release + cargo build --locked --release # Run all tests test: @@ -57,8 +57,9 @@ readiness-summary: clean: cargo clean -# Install to system +# Install for this user (does not modify PATH) install: build + mkdir -p ~/.local/bin cp target/release/panic-attack ~/.local/bin/ # Scan self (dogfood) @@ -73,15 +74,9 @@ assemblyline: lint: cargo clippy --all-targets -# Format check +# Format check (compatibility name) fmt: - cargo fmt -- --check - -# Check formatting without modifying -fmt-check: - cargo fmt --all --check -# Full CI check (fmt + lint + test) -ci: fmt lint test + cargo fmt --all -- --check # Tag and push a release (usage: just release 2.1.0) release version: @@ -204,17 +199,11 @@ chapel-diff: # Run panic-attacker pre-commit scan assail: - @command -v panic-attack >/dev/null 2>&1 && panic-attack assail . || echo "panic-attack not found — install from https://github.com/hyperpolymath/panic-attacker" + panic-attack assail . -# Self-diagnostic — checks dependencies, permissions, paths +# Local tool availability only; does not establish build or runtime compatibility doctor: - @echo "Running diagnostics for panic-attacker..." - @echo "Checking required tools..." - @command -v just >/dev/null 2>&1 && echo " [OK] just" || echo " [FAIL] just not found" - @command -v git >/dev/null 2>&1 && echo " [OK] git" || echo " [FAIL] git not found" - @echo "Checking for hardcoded paths..." - @grep -rn '$HOME\|$ECLIPSE_DIR' --include='*.rs' --include='*.ex' --include='*.res' --include='*.gleam' --include='*.sh' . 2>/dev/null | head -5 || echo " [OK] No hardcoded paths" - @echo "Diagnostics complete." + sh scripts/doctor.sh # Auto-repair common issues heal: diff --git a/PROOF-NEEDS.adoc b/PROOF-NEEDS.adoc index e893323..e09653d 100644 --- a/PROOF-NEEDS.adoc +++ b/PROOF-NEEDS.adoc @@ -58,11 +58,12 @@ signature correctness. |Hexad↔Octad persistence round-trip |`+src/storage/mod.rs+` (proptest) |*PROOF-PROGRAMME §3.1 (2026-06-04, #122)*: -`+hexad_json_roundtrip_is_identity+` proves the on-disk serde round-trip -(`+write_*_hexad+` → `+load_hexad_dir+`) is the identity on the hexad -JSON. The gateway octad projection is lossy by design, so the faithful -integrity property is the persistence round-trip, not the literal -hexad↔octad map. +`+hexad_json_roundtrip_is_identity+` tests an in-memory +`+serde_json::Value+` serialize/deserialize/serialize round-trip on generated +samples, not by a universal theorem. It does not call `+write_*_hexad+` or +`+load_hexad_dir+`; on-disk persistence correspondence remains a separate +obligation. The gateway octad projection is lossy by design, so this property +also does not establish a faithful hexad↔octad map. |=== === What Still Needs Proving diff --git a/QUICKSTART-USER.adoc b/QUICKSTART-USER.adoc index fadace1..d10c890 100644 --- a/QUICKSTART-USER.adoc +++ b/QUICKSTART-USER.adoc @@ -1,125 +1,66 @@ // SPDX-License-Identifier: CC-BY-SA-4.0 // SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell -// Template: QUICKSTART-USER.adoc — 5-minute path to working software -// Replace panic-attack, Panic Attacker — See README.adoc for details., just run, Panic Attacker started successfully. with actuals = panic-attack — Quick Start for Users -:toc: -:toclevels: 2 -== What is panic-attack? +panic-attack provides static analysis and optional stress testing. A scan result +is evidence within its reported coverage, not a certificate that a project is safe. -Panic Attacker — See README.adoc for details. +== Build the default CLI -== Prerequisites +Install Rust and Cargo using your preferred tool manager. The default CLI's +minimum Rust version is declared in `Cargo.toml` (`rust-version`, currently 1.90). +Use a compatible compiler rather than updating every language toolchain. +The optional GUI has additional compiler and system-library requirements. +Scanning a language does not require installing that language's compiler. -Before you begin, ensure you have: +The following commands assume a POSIX shell, Git, Zig configured to compile +native C dependencies through `zig cc`, a working native linker, and access +to the pinned dependencies. The default build compiles C sources from +`tree-sitter-php`. Installing Zig alone does not select it for Cargo's native +dependency build scripts; configure their C compiler before building. +These commands do not require just, mise, or Guix. -* **just** — task runner (https://github.com/casey/just[install guide]) -* Platform-specific requirements listed below - -[cols="1,3"] -|=== -| Platform | Additional Requirements - -| Linux -| See README.adoc - -| macOS -| See README.adoc - -| Windows -| See README.adoc -|=== - -== Install - -=== Option 1: Standard Install (recommended) - -[source,bash] +[source,shell] ---- -# Clone and set up git clone https://github.com/hyperpolymath/panic-attack.git cd panic-attack -just setup ----- - -The setup script will: - -* Detect your platform and shell -* Install missing dependencies (with your permission) -* Configure the application -* Offer install location choices -* Run a self-diagnostic to verify everything works - -=== Option 2: Container (via Stapeln) - -[source,bash] ----- -just stapeln-run ----- - -=== Option 3: Portable (no system changes) - -[source,bash] ----- -just install --portable --prefix=./panic-attack-portable ----- - -== First Run - -[source,bash] ----- -just run ----- - -Expected output: - -[source] ----- -Panic Attacker started successfully. ----- - -== Self-Diagnostic - -If something isn't working: - -[source,bash] ----- -just doctor ----- - -This checks all dependencies, permissions, paths, and connectivity. -If it finds issues, it will suggest fixes. - -To attempt automatic repair: - -[source,bash] ----- -just heal ----- - -== Get Help - -* **In-app**: `just run --help` -* **Guided tour**: `just tour` -* **Report a problem**: `just help-me` (pre-fills diagnostic context) -* **Wiki**: https://github.com/hyperpolymath/panic-attack/wiki - -== Uninstall - -[source,bash] ----- -just uninstall ----- - -You will be asked: - -1. Which uninstall tier (Bennett reversible, parameter-based, standard, or secure) -2. Whether to include or exclude your data -3. Whether to clear caches and LLM models - -== Next Steps - -* Read the link:README.adoc[README] for full feature overview -* Read the link:EXPLAINME.adoc[EXPLAINME] for architecture and design decisions -* Try `just tour` for a guided walkthrough +cargo build --locked --release +./target/release/panic-attack --help +./target/release/panic-attack assail . --fail-on-incomplete --output panic-report.json +---- + +A self-scan can return findings or incomplete coverage, including from deliberate +test fixtures. Do not interpret a nonzero scan exit as an installation failure; +inspect `panic-report.json` for individual findings and the coverage outcome. + +== Optional task runner and installation + +With just installed, `just --list` lists the actual recipes. `just install` +builds the default release CLI and copies it to `$HOME/.local/bin`, creating +that directory if needed. Add that directory to PATH yourself if desired. +This recipe does not install prerequisites or offer a portable/prefix option. + +`just doctor` checks whether Cargo, rustc, Git and just can run. It returns +nonzero for a missing or broken tool. It does not check compiler compatibility, +network connectivity, runtime safety, or prove a build will succeed. +Use the locked build above to check compiler and dependency compatibility. +The probe disables automatic toolchain installation with rustup 1.28.1 and +later. Older rustup versions and external tool-manager shims may still perform +their own setup; the diagnostic is not a sandbox around those programs. + +== Troubleshooting + +Record the failing command and its exit code before changing toolchains. +Report problems at https://github.com/hyperpolymath/panic-attack/issues with +the relevant error text. Review any local paths or sensitive details before +sharing logs. Platform details are optional. + +The legacy `setup.sh` still installs just through platform package managers; +it is not the cross-platform provisioning interface proposed for the estate. +The direct build path above avoids those automatic package-manager changes. +The existing `heal` recipe is not a targeted dependency repair service. +Do not use it as a substitute for diagnosing a failed build. + +There are no `stapeln-run`, `run`, or `uninstall` recipes in this checkout. +To remove a user-local installation, remove only the binary you installed. +See link:README.adoc[README] for features and analysis limitations. diff --git a/docs/ASSURANCE-AUDIT-2026-11-04.adoc b/docs/ASSURANCE-AUDIT-2026-11-04.adoc new file mode 100644 index 0000000..4e7c271 --- /dev/null +++ b/docs/ASSURANCE-AUDIT-2026-11-04.adoc @@ -0,0 +1,82 @@ +// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell (hyperpolymath) +// SPDX-License-Identifier: CC-BY-SA-4.0 += Assurance audit repair — 2026-11-04 + +At base `be6ac46`, local default Rust tests pass 653 cases with three ignored; +signing/http/sarif passes 720 with the same three ignored. These overlapping +counts are not additive coverage. Feature-enabled Clippy passes with warnings +as errors. GUI, distributed Chapel and all dynamic stress axes were not run. + +Both scanners ran against both suites and themselves. Every strict run reports +partial coverage. panic-attack analysed 64 files in cicd-suite and 102 in +proven-tests-and-benches, reporting four and three heuristic findings +respectively. Those findings require triage, not automatic defect or proof labels. + +Scheduled framework run 41390102464 fails cloning Idris2 branch `0.7.0`. +The pinned installer passes IDRIS2_VERSION directly to git; upstream's release +tag is `v0.7.0`. This caller now supplies the prefix. The producer repository +also receives normalisation and malformed-ref controls; its pin is not silently +advanced here. Hosted framework build/test acceptance remains required. + +Idris models and conditional cryptographic premises do not prove that every +Rust scanner path refines them. In particular a proptest round-trip is bounded +property testing, not a universal proof. Hypatia ingestion issue #117 and the +shared execution-evidence contract remain the appropriate integration boundary. + +Migration experiment `6addd22` changed three reusable callers to the transferred +Standards owner and deonboarded their lock entries. Runs 41816637511, 41816636052 +and 41816634641 still startup-failed; CI Integrity run 41816632936 rejected the +changed lock. The experiment was reverted, preserving the integrity gate. +A coordinated caller/callee-lock/Actions-allowlist migration remains blocked; +repository administration is unavailable through this connection. + +The Hexad property-test ledger now describes its actual in-memory serde value +round-trip. It does not execute the file write/load path, and therefore cannot +be credited as on-disk persistence coverage. + +GitHub-facing Security and Code of Conduct entry points link the existing +canonical AsciiDoc policies, without inventing new response commitments. + +== Installation entrypoint follow-up + +At `a61696431a31e5810240ea5b102ce9a57bb7d611`, just 1.36.0 rejects the +Justfile because `ci` is duplicated; `fmt-check` is duplicated too. Neither +recipe is suppressed: the fuller CI dependency list and all-target formatting +check remain. `just assail` no longer converts scanner failures into a +successful "not found" message. Installation creates the user-local bin directory +and builds with the lockfile enforced. + +The read-only doctor now fails for absent or nonfunctional tools. It checks +availability, not minimum-version compliance or successful compilation. +Bootstrap recipe selection uses `just --show`; a failed fallback doctor stops +setup before its success report. The user quickstart documents actual commands +and separates the default Rust MSRV from optional GUI requirements. + +Local evidence: 15 isolated entrypoint controls pass with upstream just 1.36.0 +Linux x86_64 musl archive SHA-256 +`bc7c9f377944f8de9cd0418b11d2955adebfa25a488c0b5e3dd2d2c0e9d732da`. +The controls reject each of three counterexamples independently: original +Justfile, original setup.sh with the corrected Justfile, and an always-successful +doctor. POSIX/Bash syntax checks and git diff whitespace checks pass. CI runs +the same controls using the checksum-pinned task runner under a five-minute +job deadline. No Rust compilation, native macOS/Windows execution, actual +package installation, or installer privilege escalation was performed in this +follow-up. Action-lock verification could not run locally without GitHub +authentication; existing action references are unchanged and hosted verification +remains required. + +Remaining provisioning work: replace generic latest-tool mise boilerplate; +align developer/maintainer quickstarts; replace broad chmod/cache-deletion heal +with bounded repair plans; integrate canonical provisioning DEED and generated +provider exports; specify opt-in platform disclosure and Bustfile-based diagnosis. +These are pending work, not capabilities supplied by this entrypoint repair. + +App-review follow-up: the fixture now includes the checked-in imported +`contractile.just`; the user command saves `panic-report.json`; and probes set +`RUSTUP_AUTO_INSTALL=0`. The expanded 16-control suite passes locally, including +an inherited auto-install setting overridden for the Rust probes. This control +checks environment propagation with stand-ins, not a real Rustup installation. +Rustup documents the opt-out from 1.28.1; earlier versions and external shims +remain outside a guaranteed no-side-effect boundary, now stated explicitly. +See https://blog.rust-lang.org/2025/03/04/Rustup-1.28.1/ and +https://rust-lang.github.io/rustup/environment-variables.html. diff --git a/scripts/ci/test-entrypoints.sh b/scripts/ci/test-entrypoints.sh new file mode 100644 index 0000000..25a7d5c --- /dev/null +++ b/scripts/ci/test-entrypoints.sh @@ -0,0 +1,68 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: MPL-2.0 +# SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell +# Hermetic tools: no compiler, package installer, network, or user files touched. +set -euo pipefail +root=$(cd "$(dirname "$0")/../.." && pwd) +just_bin=${JUST_BIN:-$(command -v just)} +just_bin=$(realpath "$just_bin") +tmp=$(mktemp -d) +trap 'rm -rf "$tmp"' EXIT +mkdir -p "$tmp/bin" "$tmp/repo/scripts" +cp "$root/Justfile" "$root/contractile.just" "$root/setup.sh" "$tmp/repo/" +cp "$root/scripts/doctor.sh" "$tmp/repo/scripts/" +ln -s /bin/sh "$tmp/bin/sh" +ln -s "$(command -v head)" "$tmp/bin/head" +ln -s "$just_bin" "$tmp/bin/just" +for tool in cargo rustc git; do + printf '#!/bin/sh\nexit 0\n' > "$tmp/bin/$tool" + chmod +x "$tmp/bin/$tool" +done +cd "$tmp/repo" +checks=0 +expect() { + local expected=$1 actual=0 + shift + "$@" > "$tmp/output" 2>&1 || actual=$? + if [[ $actual != "$expected" ]]; then + cat "$tmp/output" >&2 + printf 'expected %s, got %s: %s\n' "$expected" "$actual" "$*" >&2 + exit 1 + fi + checks=$((checks + 1)) +} +expect 0 "$just_bin" --list +expect 0 env PATH="$tmp/bin" "$just_bin" doctor +for tool in cargo rustc; do + printf '#!/bin/sh\n[ "${RUSTUP_AUTO_INSTALL:-}" = 0 ]\n' > "$tmp/bin/$tool" +done +expect 0 env PATH="$tmp/bin" RUSTUP_AUTO_INSTALL=1 "$just_bin" doctor +for tool in cargo rustc git; do + mv "$tmp/bin/$tool" "$tmp/$tool" + expect 1 env PATH="$tmp/bin" "$just_bin" doctor + grep -q "\[FAIL\] $tool" "$tmp/output" + mv "$tmp/$tool" "$tmp/bin/$tool" + printf '#!/bin/sh\nexit 7\n' > "$tmp/bin/$tool" + expect 1 env PATH="$tmp/bin" "$just_bin" doctor + printf '#!/bin/sh\nexit 0\n' > "$tmp/bin/$tool" +done +for code in 0 1 2 127; do + printf '#!/bin/sh\nexit %s\n' "$code" > "$tmp/bin/panic-attack" + chmod +x "$tmp/bin/panic-attack" + expect "$code" env PATH="$tmp/bin" "$just_bin" assail +done +rm "$tmp/bin/panic-attack" +expect 127 env PATH="$tmp/bin" "$just_bin" assail +# Bootstrap must not swallow a failed doctor or emit a success report. +printf '#!/bin/sh\nprintf Linux\n' > "$tmp/bin/uname" +chmod +x "$tmp/bin/uname" +rm "$tmp/bin/cargo" +expect 1 env PATH="$tmp/bin" /bin/sh ./setup.sh +if grep -q 'Setup Complete' "$tmp/output" || [[ -e INSTALL-SECURITY-REPORT.adoc ]]; then + echo 'bootstrap reported success after a failed diagnostic' >&2 + exit 1 +fi +# Select a real setup recipe (just --list indents recipe names). +printf 'setup:\n exit 23\n' > Justfile +expect 23 env PATH="$tmp/bin" /bin/sh ./setup.sh +printf 'entrypoint controls: %s passed\n' "$checks" diff --git a/scripts/doctor.sh b/scripts/doctor.sh new file mode 100644 index 0000000..da10ac5 --- /dev/null +++ b/scripts/doctor.sh @@ -0,0 +1,18 @@ +#!/bin/sh +# SPDX-License-Identifier: MPL-2.0 +# SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell +# Local availability probes; no repair or telemetry requested. +# Disable implicit rustup installs on rustup >= 1.28.1. Older/external shims +# may have their own side effects; these probes are not a process sandbox. +set -u +failed=0 +for tool in cargo rustc git just; do + if command -v "$tool" >/dev/null 2>&1 && RUSTUP_AUTO_INSTALL=0 "$tool" --version >/dev/null 2>&1; then + printf '[OK] %s responds to --version\n' "$tool" + else + printf '[FAIL] %s missing or unable to run\n' "$tool" >&2 + failed=1 + fi +done +printf '%s\n' 'Availability only: use cargo build --locked --release to check compiler and dependency compatibility.' +exit "$failed" diff --git a/setup.sh b/setup.sh index b057416..38ce753 100755 --- a/setup.sh +++ b/setup.sh @@ -166,6 +166,13 @@ install_just() { } # ── Main ── +# Set up the project from the current directory, installing just if needed. +# Run the first recipe whose `just --show` probe succeeds: setup, then +# setup-dev; otherwise run doctor. On success, overwrite +# INSTALL-SECURITY-REPORT.adoc with platform details and print security status. +# Exit 1 if just is unavailable after the install attempt or neither Justfile +# nor justfile is present. A failed selected recipe or report write stops the +# script with a non-zero status; failed recipe probes select the next option. main() { printf "%s=== panic-attacker Setup ===%s\n\n" "$BOLD" "$RESET" @@ -205,13 +212,13 @@ main() { # Step 3: Run just setup printf "%sStep 2: Project setup%s\n" "$BOLD" "$RESET" - if just --list 2>/dev/null | grep -q "^setup "; then + if just --show setup >/dev/null 2>&1; then just setup - elif just --list 2>/dev/null | grep -q "^setup-dev "; then + elif just --show setup-dev >/dev/null 2>&1; then just setup-dev else warn "No 'setup' recipe in Justfile — running 'just doctor' instead" - just doctor 2>/dev/null || true + just doctor fi printf "\n"