Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion .github/workflows/copilot-setup-steps.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,4 @@ jobs:
PYTHONPATH: lib/python:cli/python
run: |
python -m compileall -q cli/python lib/python tests
python -m pytest tests/test_github_workflows.py tests/test_bootstrap_docs.py -q
python -m pytest tests/test_github_workflows.py tests/test_issue_branch_policy_workflow.py tests/test_bootstrap_docs.py -q
2 changes: 1 addition & 1 deletion docs/contracts.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ before treating the fix as complete.

| Contract | Source of truth | Enforced by | Failure mode | Area |
| --- | --- | --- | --- | --- |
| GitHub workflow policy | [GitHub Workflow](github-workflow.md), [CI Supply Chain Policy](ci-supply-chain-policy.md), `.github/workflows/*.yml` | `tests/test_github_workflows.py` | Workflow permissions, concurrency, timeout, token, supported Python, or generated-guidance policy drift | CI |
| GitHub workflow policy | [GitHub Workflow](github-workflow.md), [CI Supply Chain Policy](ci-supply-chain-policy.md), `.github/workflows/*.yml` | `tests/test_github_workflows.py`, `tests/test_issue_branch_policy_workflow.py` | Workflow permissions, concurrency, timeout, token, supported Python, or generated-guidance policy drift | CI |
| Workspace manifest repository URL policy | [Workspace Manifest](workspace-manifest.md), `cli/python/base_projects/workspace_manifest.py` | `cli/python/base_projects/tests/test_workspace_manifest.py` | A documented accepted URL form is rejected, or an insecure `http://` repository URL passes silently | Workspace |
| Workspace manifest source policy | [Workspace Manifest](workspace-manifest.md), `cli/python/base_projects/workspace_pull.py` | `cli/python/base_projects/tests/test_workspace_pull.py` | `workspace.manifest_source` accepts cleartext HTTP or overwrites a local manifest after an invalid fetch | Workspace |
| Project installer template integrity | [Project Installers](project-installers.md), `templates/project-install.sh` | `cli/bash/commands/basectl/tests/repo.bats` | The maintained installer template downloads and executes a Base installer without honoring configured SHA-256 verification | Security |
Expand Down
2 changes: 1 addition & 1 deletion tests/contracts/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ run_step() {
)
}

run_step "$PYTHON_BIN" -m pytest tests/test_github_workflows.py
run_step "$PYTHON_BIN" -m pytest tests/test_github_workflows.py tests/test_issue_branch_policy_workflow.py
run_step "$PYTHON_BIN" -m pytest tests/test_contract_hardening.py
run_step "$PYTHON_BIN" -m pytest tests/test_remote_installer_policy.py
run_step "$PYTHON_BIN" -m pytest cli/python/base_setup/tests/test_remote_installers.py
Expand Down
24 changes: 24 additions & 0 deletions tests/github_workflow_test_support.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,30 @@
ISSUE_BRANCH_POLICY_WORKFLOW = WORKFLOW_DIR / "issue-branch-policy.yml"


def load_workflow(path: Path) -> dict:
payload = yaml.safe_load(path.read_text(encoding="utf-8"))
assert isinstance(payload, dict), f"{path} did not parse as a YAML mapping"
return payload


def workflow_steps(path: Path) -> list[tuple[str, int, dict]]:
workflow = load_workflow(path)
jobs = workflow.get("jobs")
assert isinstance(jobs, dict), f"{path} jobs did not parse as a YAML mapping"

steps: list[tuple[str, int, dict]] = []
for job_name, job in jobs.items():
assert isinstance(job, dict), f"{path} job {job_name} did not parse as a YAML mapping"
job_steps = job.get("steps", [])
assert isinstance(job_steps, list), f"{path} job {job_name} steps did not parse as a list"
steps.extend(
(job_name, index, step)
for index, step in enumerate(job_steps)
if isinstance(step, dict)
)
return steps


def _workflow_step_run_command(path: Path, job_name: str, step_name: str) -> str:
workflow = yaml.safe_load(path.read_text(encoding="utf-8"))
steps = workflow["jobs"][job_name]["steps"]
Expand Down
5 changes: 4 additions & 1 deletion tests/test_contract_hardening.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,9 @@ def test_contract_registry_maps_initial_review_contracts_to_enforcement() -> Non
text = CONTRACTS_DOC.read_text(encoding="utf-8")

expected_entries = {
"GitHub workflow policy": "tests/test_github_workflows.py",
"GitHub workflow policy": (
"`tests/test_github_workflows.py`, `tests/test_issue_branch_policy_workflow.py`"
),
"Workspace manifest repository URL policy": "cli/python/base_projects/tests/test_workspace_manifest.py",
"Project installer template integrity": "cli/bash/commands/basectl/tests/repo.bats",
"Base-owned remote shell installer policy": "tests/test_remote_installer_policy.py",
Expand Down Expand Up @@ -267,6 +269,7 @@ def test_contract_runner_composes_existing_policy_checks() -> None:

expected_commands = [
"tests/test_github_workflows.py",
"tests/test_issue_branch_policy_workflow.py",
"tests/test_remote_installer_policy.py",
"cli/python/base_setup/tests/test_remote_installers.py",
"cli/python/base_projects/tests/test_workspace_manifest.py",
Expand Down
Loading
Loading