Skip to content
Closed
Show file tree
Hide file tree
Changes from 9 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
26 changes: 4 additions & 22 deletions .github/workflows/python-security.yml
Original file line number Diff line number Diff line change
Expand Up @@ -232,25 +232,7 @@ jobs:
- name: Run pip-audit (hard gate on any known vulnerability)
run: |
set -euo pipefail
status=0

# 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
echo "::endgroup::"
done < <(find . -type f -name 'requirements*.txt' -not -path './.git/*')

# Audit the project itself when a PEP 621 / lock manifest exists.
if find . -maxdepth 2 -type f \
\( -name 'pyproject.toml' -o -name 'pylock.*.toml' \) \
-not -path './.git/*' | head -1 | grep -q .; then
echo "::group::pip-audit . (project manifest)"
pip-audit --strict --desc=on . || status=1
echo "::endgroup::"
fi

if [ "${status}" != "0" ]; then
echo "::error::pip-audit reported known-vulnerable Python dependencies."
exit 1
fi
# Hashed complete locks are audited with --disable-pip so pip cannot
# re-apply a stale Requires-Dist bound and label ResolutionImpossible
# as a known vulnerability (ContextualWisdomLab/.github#961).
python3 scripts/ci/pip_audit_requirements.py
8 changes: 7 additions & 1 deletion .github/workflows/strix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -543,7 +543,13 @@ 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 a stale Requires-Dist bound (strix-agent
# still declares cryptography<49) after a CVE-fixed cryptography pin
# was resolved at compile time. pull_request_target runs this file
# from the base branch, so this flag must land on main before a
# lock that needs it can install.
python3 -m pip install --disable-pip-version-check --no-cache-dir --require-hashes --no-deps -r requirements-strix-ci-hashes.txt
strix_executable="$(command -v strix || true)"
if [ -z "$strix_executable" ] || [[ "$strix_executable" != /* ]] \
|| [ ! -f "$strix_executable" ] || [ -L "$strix_executable" ] \
Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ Semantic Versioning where the repository publishes a release.

### Fixed

- Required every package line to carry a `--hash=` pin before pip-audit treats a requirements file as a complete hashed lock. A lone `--require-hashes` directive or a mixed hashed-plus-unhashed file no longer receives `--disable-pip`, which would otherwise audit an incomplete set as clean.
- Landed `--require-hashes --no-deps` on the required Strix installer and taught pip-audit to audit hashed complete locks with `--disable-pip`, so a later strix-agent 1.5.3 + cryptography 50.0.0 lock can install under `pull_request_target` and pip-audit no longer labels pip `ResolutionImpossible` as a known vulnerability (ContextualWisdomLab/.github#961, #952). A `*-hashes.txt` name without hash evidence no longer receives `--disable-pip`, and discovery skips virtualenv trees.
- 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.
- Allowed commas and ASCII parentheses in the bounded Strix changed-file path policy so legal tracked Packrat fixtures can receive exact-head security analysis, while rejecting raw `..` components before normalization and keeping controls, backslashes, whitespace ambiguity, and shell punctuation fail-closed.
- Bound each review-agent invocation key to the wrapper's complete canonical payload, including the base branch and requesting actor; altered fields with a valid-format key now fail before durable-leader election or forwarding, and wrapper write permission is job-scoped.
Expand Down
79 changes: 79 additions & 0 deletions docs/doctoring/strix-hashed-lock-no-deps.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# Strix hashed-lock install and pip-audit without pip re-resolution

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

## Incident

The required Strix workflow is `pull_request_target`: GitHub runs the **base
branch** copy of `.github/workflows/strix.yml` against the pull-request head
tree. ContextualWisdomLab/.github#961 therefore compiled a complete lock of
`strix-agent==1.5.3` plus `cryptography==50.0.0` (override for CVE-2026-39892
and CVE-2026-69247) and added `--no-deps` to the PR copy of the installer, but
the live required job still executed main's installer:

```text
pip install --require-hashes -r requirements-strix-ci-hashes.txt
```

pip re-applied `strix-agent 1.5.3 depends on cryptography<49 and >=48.0.1`
and exited `ResolutionImpossible`. The same resolver path is what
`python-security.yml` used for every `requirements*.txt` file. pip-audit then
printed `::error::pip-audit reported known-vulnerable Python dependencies`
even though no advisory was returned. A buyer watching the required security
dashboard saw two red X marks on an honest lock.

## Decision

1. Land `--require-hashes --no-deps` on **main's** Strix installer first, with
no lock change. The current main lock (`strix-agent==1.0.4` +
`cryptography==50.0.0`) is already a complete hashed set, so `--no-deps`
does not widen the install. After this lands, a later 1.5.3 lock can
install under the required base-branch workflow.
2. Audit hashed locks with `pip-audit --disable-pip` via
`scripts/ci/pip_audit_requirements.py`. Compile-time `*-overrides.txt`
files and unhashed inputs that already have a `*-hashes.txt` sibling are
not separate install sets.
3. Do not drop `cryptography==50.0.0` to satisfy the stale `<49` metadata
bound. Do not treat `ResolutionImpossible` as a vulnerability.

`python-security.yml` is `pull_request` (not `_target`), so the helper takes
effect on the same head that introduces it. Strix still needs this installer
line on the protected base before #961 can go green.

## Trust boundary

- `--no-deps` is not an unhashed install: every wheel remains hash-pinned.
- `--disable-pip` still queries the advisory database for every pinned name
and version; it only skips pip's metadata resolver.
- NVIDIA NIM / OpenCode review-agent credentials are untouched.
- No operational PII is masked.

## Verification contract

`tests/test_pip_audit_requirements.py` reconstructs the #961 lock shape and
requires `--disable-pip` for that file, a skip for the override/input pair,
and the `--no-deps` installer line on `strix.yml`. A `*-hashes.txt` name
or a lone `--require-hashes` directive without `--hash=` is not treated
as a complete lock. A mixed file with one hashed line beside unhashed
packages also stays on the resolver path. Discovery skips `.venv` trees.

## 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

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

pypa. (2025). *pip-audit: ``--disable-pip`` (hashed requirements / ``--no-deps``
only)*. https://github.com/pypa/pip-audit

Python Packaging Authority. (n.d.). *Hash-checking mode*. pip documentation.
https://pip.pypa.io/en/stable/topics/secure-installs/#hash-checking-mode
Loading
Loading