Skip to content
Closed
2 changes: 2 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@

<!-- CWL-ENTRY -->
> **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/stale-manual-rebase-label-extract.md`](docs/doctoring/stale-manual-rebase-label-extract.md).
91 changes: 91 additions & 0 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# Architecture β€” ContextualWisdomLab `.github`

This repository is the organization control plane. It is not naruon and it
does not own product data. Sibling products remain standalone modules; this
repo publishes org profile assets, reusable required workflows, and the
review/merge schedulers those products consume.

## System context

```mermaid
flowchart LR
Buyer["Commercial buyer / reviewer"]
Agents["Agents on AGENTS.md"]
Project["GitHub Project #1"]
Hub["This repo: org .github"]
Products["Owned products<br/>naruon Β· orchestrator Β· engines"]
Runner["Required workflows in each repo context"]

Buyer --> Hub
Agents --> Project
Agents --> Hub
Project --> Hub
Hub --> Runner
Runner --> Products
Products -->|"standalone or as module"| Buyer
```

## Auto-rebase stale-label path

```mermaid
flowchart TD
PR["Open same-repo PR"]
Skip{"labeled and still dirty?"}
Clear["clear_stale_manual_rebase_label"]
Rebase["perform_rebase"]
Wait["skip: await manual rebase"]

PR --> Skip
Skip -->|"yes"| Wait
Skip -->|"no"| Clear
Clear --> Rebase
```

## Control-plane data flow

```mermaid
sequenceDiagram
participant PR as Pull request
participant RW as Required workflows
participant OC as OpenCode reviewer
participant SV as sandboxed_verify / web E2E
participant MS as Merge scheduler

PR->>RW: pull_request_target on trusted base
RW->>OC: bounded evidence + NVIDIA NIM / OpenCode
OC->>SV: PoC command in isolated copy
SV-->>OC: redacted stdout/stderr + command metadata
OC-->>PR: APPROVE or request changes
MS->>PR: merge only on current-head approval + green checks
```

## Trust boundaries

- Required review workflows execute **base-branch** scripts. A PR that edits
those workflows cannot widen its own `pull_request_target` token.
- Reviewer agents stay `edit: deny`. They judge; they do not implement.
- Sandbox helpers copy the workspace, drop secret environment values unless
explicitly allowlisted by **name**, and run subprocesses with `shell=False`.
- Logs and review receipts redact credential shapes (tokens, bearer values,
known provider prefixes). They do not mask operational PII that the
control plane must process.
- LLM and scheduled agents bind `NVIDIA_NIM_API_KEY` (env may be
`NVIDIA_API_KEY`). They never use `COPILOT_GITHUB_TOKEN`. Existing
review-agent key schemes stay unchanged.

## Quality gates

`scripts/ci/` ships with 100% statement/branch coverage and 100% docstrings.
CI installs Python tools only with `pip install --require-hashes`. Contract
tests pin workflow structure and governance prose so drift fails closed.

## Related durable documents

- [`docs/CWL-MASTER-CONTEXT.md`](docs/CWL-MASTER-CONTEXT.md) β€” mission and
ecosystem.
- [`docs/agent-github-project-protocol.md`](docs/agent-github-project-protocol.md)
β€” Project #1 operation.
- [`PR_GOVERNANCE_AUDIT.md`](PR_GOVERNANCE_AUDIT.md) β€” live review/merge
contract.
- [`docs/doctoring/stale-manual-rebase-label-extract.md`](docs/doctoring/stale-manual-rebase-label-extract.md)
β€” current increment's Extract Method decision and APA 7th citations.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@ Semantic Versioning where the repository publishes a release.

- Added a trusted pull-request comment router for `@cwl-noema-review` and review-only `@opencode-agent` dispatches, with an organization sweep, exact-head receipts, repository allowlisting, fixed runners, immutable checkout pins, and a permanent 100% statement/branch/docstring quality gate.
- Added exact-base `uv.lock` materialization that reconstructs standalone nested projects with a checksum-pinned official `uv` exporter, isolated frozen/offline execution, strict exact-pin and SHA-256 output validation, and complete Python 3.10/3.14 quality evidence.
- Recorded the org control-plane architecture, including stale manual-rebase label clearing, so agents reconstruct the trust boundary from the repo instead of private memory.

### Fixed

- 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.
- Extracted stale `manual-rebase` label clearing from auto-rebase so a later base change cannot leave a resolved PR permanently blocked, without changing skip, lease-push, or conflict-label behavior.
- 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
5 changes: 4 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,10 @@ Details: `README.md` and `PR_GOVERNANCE_AUDIT.md`.
- `fuzz/` + `.clusterfuzzlite/` β€” Atheris fuzz targets for the review-output normalizer and the
ClusterFuzzLite discovery marker.
- `docs/` β€” master context, Project protocol, `org-required-workflow-rollout.md`,
`scorecard-governance.md`, SBOM inventory.
`scorecard-governance.md`, SBOM inventory. Doctoring records live under
`docs/doctoring/`. [`ARCHITECTURE.md`](ARCHITECTURE.md) is the control-plane
diagram for review, auto-rebase stale-label clearing, and merge trust
boundaries.
- `.jules/` β€” recorded performance (`bolt.md`) and security (`sentinel.md`) learnings from past work
on `scripts/ci/`; worth scanning before optimizing or hardening those scripts.

Expand Down
29 changes: 29 additions & 0 deletions docs/doctoring/stale-manual-rebase-label-extract.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Stale manual-rebase label extract

## Decision

Materialize accepts only exact SHA-256 pins or a bounded relative `-r` include; a lone `--require-hashes` line is not lock evidence.

`perform_rebase` still rebases a same-repository behind or dirty pull
request, force-pushes with lease on success, and labels plus comments on
conflict. A labeled-and-dirty candidate remains skipped upstream. The
extracted `clear_stale_manual_rebase_label` helper only removes the
`manual-rebase` label when that skip no longer applies, so a later base
change cannot leave the PR permanently blocked.

Fowler (2018) records Extract Method as the smallest way to keep a
side-effecting policy visible and independently testable. ISO/IEC
25010:2023 treats analysability and modifiability as maintainability
characteristics (International Organization for Standardization, 2023).
The helper returns audit notes and does not change git mutation,
credential, or comment behavior.

## References

Fowler, M. (2018). *Refactoring: Improving the design of existing code*
(2nd ed.). Addison-Wesley.

International Organization for Standardization. (2023). *Systems and
software engineeringβ€”Systems and software Quality Requirements and
Evaluation (SQuaRE)β€”Product quality model* (ISO/IEC 25010:2023).
https://www.iso.org/standard/78176.html
85 changes: 69 additions & 16 deletions scripts/ci/materialize_base_python_requirements.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,58 @@ def _is_candidate_lock_name(name: str) -> bool:
)



def _is_candidate_lock_path(path: pathlib.PurePosixPath) -> bool:
"""Return whether one safe tracked path can name a pip requirements lock.

In addition to conventional ``requirements*.txt`` names, repositories often
keep concrete environment closures as direct children such as
``requirements/ci.txt`` or ``service/requirements/package.txt``. Only direct
``.txt`` children of a directory named ``requirements`` gain this path-based
eligibility; content must still pass the independent complete hash-pin
validation before it reaches the trusted image build context.
"""
return _is_candidate_lock_name(path.name) or (
path.suffix == ".txt" and path.parent.name == "requirements"
)


def _is_bounded_requirement_include(line: str) -> bool:
"""Return whether one requirements include names a bounded relative file.

Includes are accepted only as a two-token ``-r``/``--requirement`` form
whose target is itself a candidate lock path written as a normalized
relative POSIX path. Absolute paths, ``.`` or ``..`` components, double
slashes, URLs, option-like targets, shell/Windows path separators,
fragments, queries, extra inline options or hashes, and includes of
non-lock files are rejected before a base-owned file can enter the
trusted build context.
The downstream installer still proves that the candidate is an independently
complete hash closure; this predicate grants syntax eligibility only.
"""
fields = line.split()
if len(fields) != 2 or fields[0] not in {"-r", "--requirement"}:
return False
target = fields[1]
if (
target.startswith(("-", "~"))
or "\\" in target
or ":" in target
or "?" in target
or "#" in target
):
return False
include_path = pathlib.PurePosixPath(target)
return (
bool(include_path.parts)
and target == include_path.as_posix()
and not include_path.is_absolute()
and "." not in include_path.parts
and ".." not in include_path.parts
and _is_candidate_lock_path(include_path)
)


def _requirement_lines(content: bytes) -> list[str]:
"""Return logical requirement lines, joining backslash line-continuations.

Expand All @@ -107,26 +159,27 @@ def _requirement_lines(content: bytes) -> list[str]:


def _is_hash_pinned(content: bytes) -> bool:
"""Return whether content carries hash pins and is safe to preflight.

Discovery is content-based rather than name-based so hash-pinned locks in any
location (a service subdirectory, ``requirements-dev.txt``,
``requirements-test.txt``) can be considered for offline coverage, while an
unpinned or PR-mutable requirements file is still excluded from the networked
build context. Hash syntax cannot prove that a file includes every transitive
dependency, so the trusted image installer separately preflights every
candidate as an independent ``--require-hashes`` closure. An empty file
carries no installable dependency and is not materialized.
"""Return whether content carries only trusted pins or bounded includes.

Discovery is content-based rather than name-based so exact hash-pinned locks
in service subdirectories and role-specific requirements files can be
considered for offline coverage. Candidate syntax is deliberately stricter
than a substring search: each package line must be an exact ``==`` pin with
one or more complete SHA-256 hashes, or a bounded relative requirements
include. A global ``--require-hashes`` directive is not trust evidence by
itself. The downstream installer separately preflights every candidate as an
independent ``pip --require-hashes`` closure, so syntax eligibility never
substitutes for dependency-closure proof.
"""
lines = _requirement_lines(content)
if not lines:
requirement_lines = [line for line in lines if line != "--require-hashes"]
if not requirement_lines:
return False
return any(line == "--require-hashes" for line in lines) or all(
"--hash=" in line or line.startswith(("-r ", "--requirement "))
for line in lines
return all(
_is_fully_hash_pinned_requirement(line)
or _is_bounded_requirement_include(line)
for line in requirement_lines
)


def _is_fully_hash_pinned_requirement(line: str) -> bool:
"""Return whether one uv-export line is an exact package pin with SHA-256 hashes."""
fields = re.split(r"\s+(?=--hash=)", line)
Expand Down
24 changes: 16 additions & 8 deletions scripts/ci/pr_auto_rebase.py
Original file line number Diff line number Diff line change
Expand Up @@ -504,21 +504,28 @@ def label_conflicted_pr(repo: str, pr: dict[str, Any], base_ref: str, *, dry_run
return tuple(notes)


def clear_stale_manual_rebase_label(repo: str, pr: dict[str, Any], *, dry_run: bool) -> tuple[str, ...]:
"""Clear a stale manual-rebase label if present, returning audit notes."""
# A candidate reaching this point that still carries the manual-rebase label
# is no longer dirty (labeled-and-dirty PRs are skipped upstream): its
# conflict was resolved by a later base change, so clear the stale label and
# let the rebase proceed instead of leaving it permanently blocked.
if has_manual_rebase_label(pr):
remove_manual_rebase_label(repo, int(pr["number"]), dry_run=dry_run)
return (f"removed stale {MANUAL_REBASE_LABEL} label (no longer dirty)",)
return ()


def perform_rebase(repo: str, pr: dict[str, Any], *, dry_run: bool) -> Decision:
"""Rebase one candidate PR, force-pushing on success or labeling on conflict."""
number = int(pr["number"])
head_ref = validate_git_ref(pr["headRefName"])
base_ref = validate_git_ref(pr["baseRefName"])
expected_head_sha = validate_git_sha(pr["headRefOid"])
token = scheduler_token()
# A candidate reaching this point that still carries the manual-rebase label
# is no longer dirty (labeled-and-dirty PRs are skipped upstream): its
# conflict was resolved by a later base change, so clear the stale label and
# let the rebase proceed instead of leaving it permanently blocked.
stale_label_notes: tuple[str, ...] = ()
if has_manual_rebase_label(pr):
remove_manual_rebase_label(repo, number, dry_run=dry_run)
stale_label_notes = (f"removed stale {MANUAL_REBASE_LABEL} label (no longer dirty)",)

stale_label_notes = clear_stale_manual_rebase_label(repo, pr, dry_run=dry_run)

with tempfile.TemporaryDirectory(prefix="pr-auto-rebase-") as workdir:
fetch_pr_refs(workdir, repo, head_ref, base_ref, token=token)
if not try_rebase(workdir, base_ref):
Expand All @@ -530,6 +537,7 @@ def perform_rebase(repo: str, pr: dict[str, Any], *, dry_run: bool) -> Decision:
stale_label_notes + notes,
)
push_force_with_lease(workdir, repo, head_ref, expected_head_sha, token=token)

return Decision(
number,
"rebased",
Expand Down
29 changes: 27 additions & 2 deletions tests/test_materialize_base_python_requirements.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@ def _created_tool_directory(path: Path) -> str:
return str(path)


def _force_linux_x86_64_installer(monkeypatch: pytest.MonkeyPatch) -> None:
"""Exercise the installer path that GitHub-hosted linux x86_64 runners use."""
monkeypatch.setattr(materializer.sys, "platform", "linux")
monkeypatch.setattr(materializer.platform, "machine", lambda: "x86_64")
materializer._install_trusted_uv.cache_clear()


def test_materializes_only_regular_hash_locks_from_exact_base(tmp_path: Path) -> None:
"""A PR-modified lock cannot enter the networked coverage image build context."""
repo = tmp_path / "repo"
Expand Down Expand Up @@ -150,9 +157,24 @@ def test_lock_name_candidates_are_pip_requirements_files() -> None:
def test_hash_pin_detection_includes_pinned_and_excludes_unpinned_or_empty() -> None:
"""Only fully hash-pinned, non-empty lock content is materialized."""
assert not materializer._is_hash_pinned(b"# comment only\n\n")
assert materializer._is_hash_pinned(b"--require-hashes\ndemo==1\n")
assert not materializer._is_hash_pinned(b"--require-hashes\ndemo==1\n")
assert materializer._is_hash_pinned(b"demo==1 --hash=sha256:" + b"a" * 64 + b"\n")
assert materializer._is_hash_pinned(b"-r other-hashes.txt\n")
assert materializer._is_hash_pinned(b"-r requirements-other.txt\n")
assert not materializer._is_hash_pinned(b"-r other-hashes.txt\n")
assert not materializer._is_hash_pinned(b"-r ./requirements-other.txt\n")
assert not materializer._is_hash_pinned(b"-r ../escape.txt\n")
assert materializer._is_bounded_requirement_include(
"--requirement requirements-other.txt"
)
assert not materializer._is_bounded_requirement_include("-r .")
assert not materializer._is_bounded_requirement_include("-r -evil.txt")
assert not materializer._is_bounded_requirement_include("-r ~evil.txt")
assert not materializer._is_bounded_requirement_include("-r C:foo.txt")
assert not materializer._is_bounded_requirement_include("-r foo?bar.txt")
assert not materializer._is_bounded_requirement_include("-r foo#bar.txt")
assert not materializer._is_bounded_requirement_include(r"-r foo\\bar.txt")
assert not materializer._is_bounded_requirement_include("-r")
assert not materializer._is_bounded_requirement_include("-r /abs/requirements.txt")
assert not materializer._is_hash_pinned(b"untrusted==1\n")
# uv export / pip-compile multi-line continuation format (spec, then --hash= lines).
assert materializer._is_hash_pinned(
Expand Down Expand Up @@ -644,6 +666,7 @@ def test_install_trusted_uv_verifies_version_and_caches_path(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
"""The installer writes one executable, verifies its version, and caches it."""
_force_linux_x86_64_installer(monkeypatch)
tool_dir = tmp_path / "uv"
monkeypatch.setattr(
materializer.tempfile,
Expand Down Expand Up @@ -690,6 +713,7 @@ def test_install_trusted_uv_rejects_version_process_failures(
failure: OSError | subprocess.TimeoutExpired,
) -> None:
"""A missing or hung downloaded executable is removed and rejected."""
_force_linux_x86_64_installer(monkeypatch)
tool_dir = tmp_path / "uv"
monkeypatch.setattr(
materializer.tempfile,
Expand Down Expand Up @@ -721,6 +745,7 @@ def test_install_trusted_uv_rejects_wrong_version_or_exit_status(
completed: subprocess.CompletedProcess[bytes],
) -> None:
"""Unexpected version output or a nonzero status cannot satisfy the pin."""
_force_linux_x86_64_installer(monkeypatch)
tool_dir = tmp_path / f"uv-{completed.returncode}-{len(completed.stdout)}"
monkeypatch.setattr(
materializer.tempfile,
Expand Down
Loading