Skip to content
Closed
Show file tree
Hide file tree
Changes from 10 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
17 changes: 16 additions & 1 deletion .github/workflows/python-security.yml
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,22 @@ jobs:
# Audit every discovered requirements file.
while IFS= read -r req; do
echo "::group::pip-audit -r ${req}"
pip-audit --strict --desc=on -r "${req}" || status=1
# The Strix 1.5.3 lock keeps cryptography==50.0.0. pip-audit's
# resolver re-applies the stale upstream cryptography<49 bound and
# labels that ResolutionImpossible as a vulnerability. The
# unhashed compile input is not an audit target. The hashed lock
# is a URL pin; --disable-pip cannot read that form, so rewrite
# it to name==version from the PEP 427 filename first.
if [ "$(basename "${req}")" = "requirements-strix-ci.txt" ]; then
echo "Skipping unhashed Strix compile input; hashed sibling is the audit target."
elif [ "$(basename "${req}")" = "requirements-strix-ci-hashes.txt" ]; then
prepared="${RUNNER_TEMP}/strix-pip-audit.txt"
python3 scripts/ci/prepare_strix_lock_for_pip_audit.py \
--input "${req}" --output "${prepared}"
pip-audit --strict --desc=on --disable-pip -r "${prepared}" || status=1
else
pip-audit --strict --desc=on -r "${req}" || status=1
fi
echo "::endgroup::"
done < <(find . -type f -name 'requirements*.txt' -not -path './.git/*')

Expand Down
12 changes: 11 additions & 1 deletion .github/workflows/strix-changed-path-quality-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,22 @@ on:
branches: [main]
paths:
- ".github/workflows/strix-changed-path-quality-ci.yml"
- ".github/workflows/strix.yml"
- "CHANGELOG.md"
- "docs/doctoring/strix-agent-cryptography-override.md"
- "docs/doctoring/strix-legal-git-paths.md"
- "docs/doctoring/strix-quality-timeout-fixtures.md"
- "requirements-strix-ci-overrides.txt"
- "scripts/ci/compile_strix_ci_lock.sh"
- "scripts/ci/prepare_strix_lock_for_pip_audit.py"
- "scripts/ci/rewrite_strix_agent_cryptography_bound.py"
- "scripts/ci/strix_quick_gate.sh"
- "scripts/ci/test_strix_quick_gate.sh"
- "tests/test_prepare_strix_lock_for_pip_audit.py"
- "tests/test_rewrite_strix_agent_cryptography_bound.py"
- "tests/test_strix_agent_cryptography_override.py"
- "tests/test_strix_changed_path_policy.py"
- "vendor/strix/"
- "tests/test_strix_workflow_dependency_hashes.py"
- "tests/test_strix_quality_timeout_fixture_budget.py"

Expand Down Expand Up @@ -66,6 +76,6 @@ jobs:
test "$(git rev-parse HEAD)" = "${{ github.event.pull_request.head.sha || github.sha }}"
python -m coverage run -m pytest tests -q
bash scripts/ci/test_strix_quick_gate.sh
python -m compileall -q tests/test_strix_changed_path_policy.py tests/test_strix_workflow_dependency_hashes.py tests/test_strix_quality_timeout_fixture_budget.py
python -m compileall -q scripts/ci/prepare_strix_lock_for_pip_audit.py tests/test_prepare_strix_lock_for_pip_audit.py tests/test_rewrite_strix_agent_cryptography_bound.py tests/test_strix_agent_cryptography_override.py tests/test_strix_changed_path_policy.py tests/test_strix_workflow_dependency_hashes.py tests/test_strix_quality_timeout_fixture_budget.py
bash -n scripts/ci/strix_quick_gate.sh
git diff --exit-code
19 changes: 18 additions & 1 deletion .github/workflows/strix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -543,7 +543,24 @@ jobs:
# private install umask before creating the credential-bearing Strix
# entry point; the runtime gate still rejects any later relaxation.
umask 022
python3 -m pip install --disable-pip-version-check --no-cache-dir --require-hashes -r requirements-strix-ci-hashes.txt
# The compiled lock is the complete closed set. --no-deps is required
# so pip does not re-apply strix-agent's stale cryptography<49 bound
# after the CVE-50 override was resolved at compile time.
python3 -m pip install --disable-pip-version-check --no-cache-dir --require-hashes --no-deps -r requirements-strix-ci-hashes.txt
python3 - <<'PY'
import importlib.metadata as metadata
import sys

expected = {"strix-agent": "1.5.3", "cryptography": "50.0.0"}
for name, version in expected.items():
loaded = metadata.version(name)
if loaded != version:
print(
f"::error::Installed {name}=={loaded}, expected {version}.",
file=sys.stderr,
)
sys.exit(1)
PY
strix_executable="$(command -v strix || true)"
if [ -z "$strix_executable" ] || [[ "$strix_executable" != /* ]] \
|| [ ! -f "$strix_executable" ] || [ -L "$strix_executable" ] \
Expand Down
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@
> **Agents: read the master context FIRST.** Before any work, read [`docs/CWL-MASTER-CONTEXT.md`](docs/CWL-MASTER-CONTEXT.md) (mission · naruon-as-platform + inter-component UML · cross-cutting disciplines · conventions · roadmap · current state), the live **GitHub Project #1** <https://github.com/orgs/ContextualWisdomLab/projects/1> (work/roadmap source of truth), the full spec **ContextualWisdomLab/naruon#974**, and operate the Project per [`docs/agent-github-project-protocol.md`](docs/agent-github-project-protocol.md). The repo/Project — not any private agent memory — is the source of truth.

Materialize accepts only exact SHA-256 pins or a bounded relative `-r` include (no `.`/`..`); a lone `--require-hashes` directive is not trust evidence. See [`docs/doctoring/hourly-nvidia-nim-autofix.md`](docs/doctoring/hourly-nvidia-nim-autofix.md).
The Strix CI lock keeps `strix-agent==1.5.3` with `cryptography==50.0.0` through `requirements-strix-ci-overrides.txt` and `./scripts/ci/compile_strix_ci_lock.sh`; install that complete hashed lock with `--no-deps`. The lock also prefers a METADATA-patched official 1.5.3 wheel so current `main`'s resolver-based installer can still resolve both pins. See [`docs/doctoring/strix-agent-cryptography-override.md`](docs/doctoring/strix-agent-cryptography-override.md).
Conflict-scope roots fail closed when the immediate parent directory is a symbolic link.
13 changes: 13 additions & 0 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,17 @@ sequenceDiagram
- Rust remains the psychometric arithmetic owner. Repair never substitutes
Python for scoring math.

## Required Strix lock

The org-required Strix workflow installs a complete hashed lock. Upstream
`strix-agent==1.5.3` still declares `cryptography<49`, so compile-time
override keeps `cryptography==50.0.0` (CVE-2026-69247 PKCS#7 timing
oracle; also above CVE-2026-39892). CI then installs with
`pip install --require-hashes --no-deps` and fail-closes unless
`importlib.metadata` reports both pins. The missing-artifact gate is
unchanged: console severity markers are not a passing report. See
[`docs/doctoring/strix-agent-cryptography-override.md`](docs/doctoring/strix-agent-cryptography-override.md).

## Quality gates

`scripts/ci/` ships with 100% statement/branch coverage and 100% docstrings.
Expand All @@ -106,5 +117,7 @@ tests pin workflow structure and governance prose so drift fails closed.
contract.
- [`docs/doctoring/hourly-nvidia-nim-autofix.md`](docs/doctoring/hourly-nvidia-nim-autofix.md)
— current increment's repair-worker decision and APA 7th citations.
- [`docs/doctoring/strix-agent-cryptography-override.md`](docs/doctoring/strix-agent-cryptography-override.md)
— Strix 1.5.3 report persist with cryptography 50.0.0 override.
- [`docs/doctoring/fast-mlsirm-hourly-review-caller.md`](docs/doctoring/fast-mlsirm-hourly-review-caller.md)
— product-specific psychometric repair heartbeat and scientific gates.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ Semantic Versioning where the repository publishes a release.

### Fixed

- Pin required Strix to `strix-agent==1.5.3` so a completed scan writes a durable report artifact, keep `cryptography==50.0.0` (CVE-2026-69247 / CVE-2026-39892) via a compile-time override, and install the complete hashed lock with `--no-deps` so pip cannot re-apply the stale `cryptography<49` bound. Until that installer is on protected `main`, the lock also prefers a METADATA-patched official 1.5.3 wheel so `pip install --require-hashes` without `--no-deps` can resolve both pins. pip-audit skips the unhashed compile input and audits a prepared `name==version` copy of the hashed lock with `--disable-pip`, so it neither re-resolves `strix-agent==1.5.3` against cryptography 50 nor rejects the install-time URL pin. The fail-closed missing-artifact gate is unchanged.
- Materialized base Python locks only when every package line is an exact SHA-256 pin or a bounded relative `-r`/`--requirement` include. A lone `--require-hashes` directive, a dotted include such as `./lock.txt`, or `-r other-hashes.txt` no longer enters the trusted build context.
- Refused a conflict-scope repository root whose immediate parent is a symbolic link, so a swapped parent cannot redirect the canonical worktree after the last-component check (CWE-367).
- Bounded the Strix quality self-test's deterministic timeout fixtures to 3-second process and 5-second fake-sleep budgets so exact-head policy evidence completes inside the existing job limit without changing production Strix scanner timeouts, providers, credentials, or review semantics.
Expand Down
12 changes: 8 additions & 4 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,14 +96,18 @@ e.g.:
```bash
uv pip compile --generate-hashes --python-version 3.12 --python-platform x86_64-manylinux_2_28 requirements-bandit-ci.txt -o requirements-bandit-ci-hashes.txt
uv pip compile --generate-hashes --python-version 3.12 --python-platform x86_64-manylinux_2_28 requirements-pip-audit-ci.txt -o requirements-pip-audit-ci-hashes.txt
uv pip compile --generate-hashes --python-version 3.13 --python-platform x86_64-manylinux_2_28 --output-file requirements-strix-ci-hashes.txt requirements-strix-ci.txt
./scripts/ci/compile_strix_ci_lock.sh
./scripts/ci/compile_opencode_review_lock.sh
```

Note the per-file Python versions differ (bandit/pip-audit: 3.12; strix: 3.13; OpenCode
review: 3.14). The OpenCode review generator always passes `--upgrade` so an existing output
file cannot preserve hashes from the previous Python target, and records itself as the lock's
repeatable compile command.
review: 3.14). The Strix generator records itself as the lock's repeatable compile command
and applies `requirements-strix-ci-overrides.txt` so `strix-agent==1.5.3` can keep
`cryptography==50.0.0`. After compile it rewrites the official 1.5.3 manylinux
wheel metadata and lock `--find-links` so a resolver-based `pip install
--require-hashes` can still install cryptography 50.0.0. The OpenCode review generator always passes `--upgrade` so an
existing output file cannot preserve hashes from the previous Python target, and records
itself as the lock's repeatable compile command.

## Conventions and gotchas specific to this repo

Expand Down
139 changes: 139 additions & 0 deletions docs/doctoring/strix-agent-cryptography-override.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
# Strix 1.5.3 atomic report persist + cryptography 50 override

검토 기준일: **2026-08-16**

## Incident

The required Strix check is the central `pull_request_target` /
`repository_dispatch` workflow in this repository. On current `main`
(`c47afc2dc68488292c1db7c9d6f82dcd5360f181`) consumer runs still install
`strix-agent==1.0.4` with `cryptography==50.0.0`. Recent failures that
were re-read for this increment, not only ContextualWisdomLab/.github#952:

| Consumer | Run | Observed terminal shape |
|---|---|---|
| ContextualWisdomLab/mightyETL#315 | [31950271564](https://github.com/ContextualWisdomLab/.github/actions/runs/31950271564) / job 95172565509 | `Tool execute not found in agent strix`, then `No Strix vulnerability report artifact was produced; log-only severity markers are incomplete evidence` |
| ContextualWisdomLab/.github#1023 | [31952135549](https://github.com/ContextualWisdomLab/.github/actions/runs/31952135549) / job 95177171349 | `Penetration test completed` / `Vulnerabilities MEDIUM: 1`, then exit 2 and `Strix report artifacts emitted warning/fatal/denied/timeout output; failing closed` |
| ContextualWisdomLab/noema#392 | [31950935010](https://github.com/ContextualWisdomLab/.github/actions/runs/31950935010) | required `strix` red on the same 1.0.4 lock |

The fail-closed missing-artifact rule in `scripts/ci/strix_quick_gate.sh`
(ContextualWisdomLab/.github#891) is working as designed and is not
weakened here. Console TUI lines such as `Vulnerabilities MEDIUM: 1` are
not a passing report.

The crash-after-print shape is the 1.0.4 scanner. Upstream 1.1.0 added
atomic CSV/MD writes, and 1.4.0+ quit after scan instead of hosting a
local viewer. Latest PyPI release remains `strix-agent==1.5.3` and still
declares `cryptography>=48.0.1,<49` (usestrix/strix#859, Intel macOS
universal2 wheel). See ContextualWisdomLab/.github#952.

A one-line bump is blocked because `uv pip compile` without an override
refuses `strix-agent==1.5.3` + `cryptography==50.0.0`. Cryptography 50.0.0
is the floor that closes CVE-2026-69247 (PKCS#7 EnvelopedData
Bleichenbacher-style timing/error oracle in `pkcs7_decrypt_der` /
`pkcs7_decrypt_pem` / `pkcs7_decrypt_smime`, introduced in 44.0.0). It
also sits above CVE-2026-39892 (non-contiguous buffer overflow, fixed in
46.0.7).

## Decision

1. Pin `strix-agent==1.5.3` and keep `cryptography==50.0.0`. Materialize
only exact SHA-256 pins or a bounded relative `-r` include; a lone
`--require-hashes` line is not lock evidence.
2. Resolve the declared upper bound only at compile time through
`requirements-strix-ci-overrides.txt` and
`scripts/ci/compile_strix_ci_lock.sh`.
3. Install the complete hashed lock with
`pip install --require-hashes --no-deps`. The lock already lists every
wheel; `--no-deps` prevents pip from re-applying the stale
`cryptography<49` metadata bound that would otherwise make CI
uninstallable. Immediately after install, the workflow fail-closes
unless `importlib.metadata` reports `strix-agent==1.5.3` and
`cryptography==50.0.0`.
4. Because required Strix is `pull_request_target`, protected `main` still
installs this PR-head lock without `--no-deps` until
ContextualWisdomLab/.github#969 merges. The official 1.5.3 manylinux
x86_64 wheel is therefore rewritten by
`scripts/ci/rewrite_strix_agent_cryptography_bound.py` so its
`Requires-Dist` line is `cryptography>=48.0.1` (Apache-2.0 upstream
bytes otherwise unchanged). The hashed lock pins that wheel through a
direct raw GitHub URL at the commit that published it, so pip cannot
fetch the official PyPI artifact and fail the hash check. Main's
resolver can then install
`strix-agent==1.5.3` and `cryptography==50.0.0` together. pip-audit
skips the unhashed compile input and audits a prepared copy of this
hashed lock with `--disable-pip`. `--disable-pip` cannot pin a URL
requirement, so `scripts/ci/prepare_strix_lock_for_pip_audit.py`
rewrites `strix-agent @ <url>` to `strix-agent==1.5.3` from the PEP
427 filename. That keeps pip-audit from re-querying the stale PyPI
metadata and labeling `ResolutionImpossible` as a vulnerability.
5. Do not scrape console TUI lines as a substitute report. The gate still
requires a durable artifact and still fail-closes on warning / fatal /
denied / timeout report signals.

A live `pip`/`uv` install of this hashed lock with `--require-hashes
--no-deps` imported `strix`, ran `strix --help` (including the
non-interactive “exits on completion” path), and loaded
`cryptography==50.0.0` together with `strix-agent==1.5.3` on CPython
3.12.3 and 3.13.15. The same lock with `--require-hashes` and no
`--no-deps` now dry-runs to `Would install ... cryptography-50.0.0
... strix-agent-1.5.3` instead of `ResolutionImpossible`.

## Trust boundary

- The fail-closed missing-artifact rule is unchanged.
- The override file may contain only `cryptography==50.0.0`.
- Hashes remain required. `--no-deps` is not an unhashed install.
- The vendored wheel changes only the cryptography `Requires-Dist` line
and its `RECORD` digest. The official source URL and SHA-256 stay in
`vendor/strix/SOURCE.json`.
- NVIDIA NIM / OpenCode credentials are untouched. This path never uses
`COPILOT_GITHUB_TOKEN`.

## Verification contract

`tests/test_strix_agent_cryptography_override.py` proves the input pin,
the singleton override, both versions in the compiled lock, the compile
script flags, the `--no-deps` install line, the post-install
`strix-agent==1.5.3` / `cryptography==50.0.0` metadata check, pip-audit
skipping the unhashed compile input, `--disable-pip` on a prepared
`name==version` copy of this hashed lock, and that quality CI retriggers
when any of those files change.
`tests/test_rewrite_strix_agent_cryptography_bound.py` proves the
METADATA-only wheel rewrite, RECORD update, direct-URL lock rewrite,
and that the committed wheel no longer declares `cryptography<49`.

## Rollback

If 1.5.3 regresses a required scan, revert the pin to 1.0.4 and the
`--no-deps` install together. Do not drop cryptography 50.0.0 to satisfy
the stale `<49` bound.

## After merge

Consumer required `strix` checks read this workflow from protected
`main`. After this lands, a new same-head scan installs 1.5.3, persists
the report directory, and lets the existing gate judge that artifact.
Findings at or above `STRIX_FAIL_ON_MIN_SEVERITY` still fail the check.
A completed scan with no threshold finding can go green.

## References (APA 7th)

GitHub. (2026). *Cryptography vulnerable to buffer overflow if
non-contiguous buffers were passed to APIs (CVE-2026-39892,
GHSA-p423-j2cm-9vmq)*. GitHub Advisory Database.
https://github.com/advisories/GHSA-p423-j2cm-9vmq

GitHub. (2026). *PKCS#7 decryption timing oracle in pyca/cryptography
(CVE-2026-69247, GHSA-g6cj-pr64-35w5)*. GitHub Advisory Database.
https://github.com/advisories/GHSA-g6cj-pr64-35w5

MITRE. (n.d.). *CWE-208: Observable timing discrepancy*. CWE List.
https://cwe.mitre.org/data/definitions/208.html

National Institute of Standards and Technology. (2026).
*CVE-2026-69247*. National Vulnerability Database.
https://nvd.nist.gov/vuln/detail/CVE-2026-69247

Strix. (2026). *strix-agent 1.5.3 release notes* (atomic CSV/MD writes;
quit after scan). https://github.com/usestrix/strix/releases
Loading
Loading