tool-compass 2.2.2__tar.gz → 2.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tool_compass-2.4.0/.dockerignore +84 -0
- {tool_compass-2.2.2 → tool_compass-2.4.0}/.env.example +4 -2
- tool_compass-2.4.0/.github/dependabot.yml +89 -0
- {tool_compass-2.2.2 → tool_compass-2.4.0}/.github/workflows/ci.yml +100 -13
- tool_compass-2.4.0/.github/workflows/publish.yml +285 -0
- tool_compass-2.4.0/.github/workflows/release-binaries.yml +175 -0
- tool_compass-2.4.0/.github/workflows/release.yml +165 -0
- {tool_compass-2.2.2 → tool_compass-2.4.0}/.gitignore +14 -0
- tool_compass-2.4.0/.pre-commit-config.yaml +55 -0
- tool_compass-2.4.0/CHANGELOG.md +486 -0
- {tool_compass-2.2.2 → tool_compass-2.4.0}/CONTRIBUTING.md +45 -26
- {tool_compass-2.2.2 → tool_compass-2.4.0}/Dockerfile +16 -6
- {tool_compass-2.2.2 → tool_compass-2.4.0}/Makefile +15 -8
- {tool_compass-2.2.2 → tool_compass-2.4.0}/PKG-INFO +52 -33
- {tool_compass-2.2.2 → tool_compass-2.4.0}/README.md +49 -31
- tool_compass-2.4.0/SCORECARD.md +36 -0
- {tool_compass-2.2.2 → tool_compass-2.4.0}/SECURITY.md +22 -7
- {tool_compass-2.2.2 → tool_compass-2.4.0}/SHIP_GATE.md +2 -2
- {tool_compass-2.2.2 → tool_compass-2.4.0}/analytics.py +124 -36
- {tool_compass-2.2.2 → tool_compass-2.4.0}/backend_client_mcp.py +81 -10
- tool_compass-2.4.0/backend_client_simple.py +1815 -0
- tool_compass-2.4.0/bootstrap.py +128 -0
- {tool_compass-2.2.2 → tool_compass-2.4.0}/chain_indexer.py +139 -11
- tool_compass-2.4.0/cli.py +1858 -0
- {tool_compass-2.2.2 → tool_compass-2.4.0}/compass_config.example.json +16 -1
- {tool_compass-2.2.2 → tool_compass-2.4.0}/config.py +465 -17
- tool_compass-2.4.0/embedder.py +934 -0
- {tool_compass-2.2.2 → tool_compass-2.4.0}/gateway.py +1183 -275
- {tool_compass-2.2.2 → tool_compass-2.4.0}/indexer.py +365 -156
- {tool_compass-2.2.2 → tool_compass-2.4.0}/llms.txt +20 -4
- {tool_compass-2.2.2 → tool_compass-2.4.0}/pyproject.toml +40 -6
- tool_compass-2.4.0/scripts/regenerate-scorecard.sh +116 -0
- tool_compass-2.4.0/scripts/verify-metrics.sh +125 -0
- {tool_compass-2.2.2 → tool_compass-2.4.0}/sync_manager.py +310 -37
- {tool_compass-2.2.2 → tool_compass-2.4.0}/tool_manifest.py +32 -4
- tool_compass-2.4.0/ui.py +1955 -0
- tool_compass-2.2.2/.dockerignore +0 -56
- tool_compass-2.2.2/.github/dependabot.yml +0 -24
- tool_compass-2.2.2/.github/workflows/publish.yml +0 -178
- tool_compass-2.2.2/AUDIT_REPORT.md +0 -245
- tool_compass-2.2.2/CHANGELOG.md +0 -269
- tool_compass-2.2.2/README.es.md +0 -324
- tool_compass-2.2.2/README.fr.md +0 -324
- tool_compass-2.2.2/README.hi.md +0 -323
- tool_compass-2.2.2/README.it.md +0 -324
- tool_compass-2.2.2/README.ja.md +0 -322
- tool_compass-2.2.2/README.pt-BR.md +0 -324
- tool_compass-2.2.2/README.zh.md +0 -324
- tool_compass-2.2.2/SCORECARD.md +0 -36
- tool_compass-2.2.2/assets/logo.png +0 -0
- tool_compass-2.2.2/backend_client_simple.py +0 -861
- tool_compass-2.2.2/bootstrap.py +0 -80
- tool_compass-2.2.2/cli.py +0 -283
- tool_compass-2.2.2/docs/assets/social-preview.png +0 -0
- tool_compass-2.2.2/docs/assets/social-preview.svg +0 -41
- tool_compass-2.2.2/docs/assets/tool-compass-logo-dark-bg.jpg +0 -0
- tool_compass-2.2.2/embedder.py +0 -432
- tool_compass-2.2.2/logo.png +0 -0
- tool_compass-2.2.2/site/astro.config.mjs +0 -30
- tool_compass-2.2.2/site/package-lock.json +0 -7031
- tool_compass-2.2.2/site/package.json +0 -18
- tool_compass-2.2.2/site/src/content/docs/handbook/architecture.md +0 -140
- tool_compass-2.2.2/site/src/content/docs/handbook/beginners.md +0 -170
- tool_compass-2.2.2/site/src/content/docs/handbook/configuration.md +0 -137
- tool_compass-2.2.2/site/src/content/docs/handbook/getting-started.md +0 -157
- tool_compass-2.2.2/site/src/content/docs/handbook/index.md +0 -30
- tool_compass-2.2.2/site/src/content/docs/handbook/operations.md +0 -173
- tool_compass-2.2.2/site/src/content/docs/handbook/tools.md +0 -110
- tool_compass-2.2.2/site/src/content.config.ts +0 -7
- tool_compass-2.2.2/site/src/pages/index.astro +0 -33
- tool_compass-2.2.2/site/src/site-config.ts +0 -158
- tool_compass-2.2.2/site/src/styles/global.css +0 -3
- tool_compass-2.2.2/site/src/styles/starlight-custom.css +0 -17
- tool_compass-2.2.2/site/tsconfig.json +0 -5
- tool_compass-2.2.2/ui.py +0 -1337
- {tool_compass-2.2.2 → tool_compass-2.4.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {tool_compass-2.2.2 → tool_compass-2.4.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {tool_compass-2.2.2 → tool_compass-2.4.0}/CODE_OF_CONDUCT.md +0 -0
- {tool_compass-2.2.2 → tool_compass-2.4.0}/LICENSE +0 -0
- {tool_compass-2.2.2 → tool_compass-2.4.0}/_version.py +0 -0
- {tool_compass-2.2.2 → tool_compass-2.4.0}/docker-compose.yml +0 -0
- {tool_compass-2.2.2 → tool_compass-2.4.0}/docs/index.md +0 -0
- {tool_compass-2.2.2 → tool_compass-2.4.0}/fly.toml +0 -0
- {tool_compass-2.2.2 → tool_compass-2.4.0}/requirements-dev.txt +0 -0
- {tool_compass-2.2.2 → tool_compass-2.4.0}/requirements.txt +0 -0
- {tool_compass-2.2.2 → tool_compass-2.4.0}/scripts/check-org-urls.sh +0 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Git
|
|
2
|
+
.git
|
|
3
|
+
.gitignore
|
|
4
|
+
|
|
5
|
+
# Docker
|
|
6
|
+
Dockerfile
|
|
7
|
+
docker-compose.yml
|
|
8
|
+
.dockerignore
|
|
9
|
+
|
|
10
|
+
# Python
|
|
11
|
+
__pycache__
|
|
12
|
+
*.py[cod]
|
|
13
|
+
*$py.class
|
|
14
|
+
*.so
|
|
15
|
+
.Python
|
|
16
|
+
venv/
|
|
17
|
+
.venv/
|
|
18
|
+
ENV/
|
|
19
|
+
env/
|
|
20
|
+
.eggs/
|
|
21
|
+
*.egg-info/
|
|
22
|
+
*.egg
|
|
23
|
+
|
|
24
|
+
# IDE
|
|
25
|
+
.vscode/
|
|
26
|
+
.idea/
|
|
27
|
+
*.swp
|
|
28
|
+
*.swo
|
|
29
|
+
|
|
30
|
+
# Testing
|
|
31
|
+
.pytest_cache/
|
|
32
|
+
.coverage
|
|
33
|
+
htmlcov/
|
|
34
|
+
.tox/
|
|
35
|
+
.hypothesis/
|
|
36
|
+
.benchmarks/
|
|
37
|
+
|
|
38
|
+
# Build artifacts
|
|
39
|
+
dist/
|
|
40
|
+
build/
|
|
41
|
+
*.manifest
|
|
42
|
+
*.spec
|
|
43
|
+
|
|
44
|
+
# OS files
|
|
45
|
+
.DS_Store
|
|
46
|
+
Thumbs.db
|
|
47
|
+
|
|
48
|
+
# Local development files
|
|
49
|
+
*.local.json
|
|
50
|
+
.env.local
|
|
51
|
+
.env*
|
|
52
|
+
|
|
53
|
+
# Gradio cache
|
|
54
|
+
flagged/
|
|
55
|
+
|
|
56
|
+
# Keep db directory structure but not contents
|
|
57
|
+
db/*.db
|
|
58
|
+
db/*.hnsw
|
|
59
|
+
!db/.gitkeep
|
|
60
|
+
|
|
61
|
+
# Sources that don't belong in the production image (CT-B-004).
|
|
62
|
+
# These are intentionally excluded so a future regression to
|
|
63
|
+
# `COPY . .` doesn't silently ship them.
|
|
64
|
+
tests/
|
|
65
|
+
docs/
|
|
66
|
+
site/
|
|
67
|
+
archive/
|
|
68
|
+
.github/
|
|
69
|
+
.claude/
|
|
70
|
+
# Translation READMEs (re-run on TranslateGemma 12B; not runtime artifacts)
|
|
71
|
+
README.ja.md
|
|
72
|
+
README.zh.md
|
|
73
|
+
README.es.md
|
|
74
|
+
README.fr.md
|
|
75
|
+
README.hi.md
|
|
76
|
+
README.it.md
|
|
77
|
+
README.pt-BR.md
|
|
78
|
+
# Audit / governance docs — not needed at runtime
|
|
79
|
+
SCORECARD.md
|
|
80
|
+
SHIP_GATE.md
|
|
81
|
+
CODE_OF_CONDUCT.md
|
|
82
|
+
CONTRIBUTING.md
|
|
83
|
+
SECURITY.md
|
|
84
|
+
CHANGELOG.md
|
|
@@ -55,8 +55,10 @@ GRADIO_SERVER_PORT=7860
|
|
|
55
55
|
# Analytics (optional)
|
|
56
56
|
# =============================================================================
|
|
57
57
|
|
|
58
|
-
# Disable analytics tracking
|
|
58
|
+
# Disable analytics tracking (truthy: 1/true/yes/on). Overrides the
|
|
59
|
+
# analytics_enabled config-file key when set.
|
|
59
60
|
# TOOL_COMPASS_ANALYTICS_DISABLED=true
|
|
60
61
|
|
|
61
|
-
# Hot cache size (number of frequently used tools to pre-load)
|
|
62
|
+
# Hot cache size (number of frequently used tools to pre-load). Overrides the
|
|
63
|
+
# hot_cache_size config-file key; clamped to a safe minimum like any config value.
|
|
62
64
|
# TOOL_COMPASS_HOT_CACHE_SIZE=10
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
updates:
|
|
3
|
+
# =============================================================================
|
|
4
|
+
# pip — Python runtime + dev dependencies
|
|
5
|
+
# =============================================================================
|
|
6
|
+
- package-ecosystem: "pip"
|
|
7
|
+
directory: "/"
|
|
8
|
+
schedule:
|
|
9
|
+
interval: "monthly"
|
|
10
|
+
open-pull-requests-limit: 3
|
|
11
|
+
groups:
|
|
12
|
+
# Minor + patch only so breaking majors open as SEPARATE PRs.
|
|
13
|
+
# (Avoids the ollama-intern PR #4 incident where 5 breaking majors
|
|
14
|
+
# shipped bundled under a wildcard group.)
|
|
15
|
+
all-pip:
|
|
16
|
+
patterns: ["*"]
|
|
17
|
+
update-types: ["minor", "patch"]
|
|
18
|
+
|
|
19
|
+
# Daily security-only overlay (CT-B-006) — CVE updates from the GitHub
|
|
20
|
+
# Advisory Database don't wait the monthly cadence. open-pull-requests-limit
|
|
21
|
+
# raised to 10 since these are infrequent and load-bearing.
|
|
22
|
+
# NOTE: Dependabot security advisories are auto-emitted; this second entry
|
|
23
|
+
# exists to give them their own schedule/labels/PR cap independent of the
|
|
24
|
+
# monthly version-update entry above. The `allow: dependency-type: all`
|
|
25
|
+
# block scopes this entry to all dependencies; security advisories are
|
|
26
|
+
# always opened regardless of the version-update grouping rules.
|
|
27
|
+
- package-ecosystem: "pip"
|
|
28
|
+
directory: "/"
|
|
29
|
+
schedule:
|
|
30
|
+
interval: "daily"
|
|
31
|
+
open-pull-requests-limit: 10
|
|
32
|
+
allow:
|
|
33
|
+
- dependency-type: "all"
|
|
34
|
+
labels:
|
|
35
|
+
- "security"
|
|
36
|
+
- "dependencies"
|
|
37
|
+
|
|
38
|
+
# =============================================================================
|
|
39
|
+
# github-actions — workflow file action references
|
|
40
|
+
# =============================================================================
|
|
41
|
+
- package-ecosystem: "github-actions"
|
|
42
|
+
directory: "/"
|
|
43
|
+
schedule:
|
|
44
|
+
interval: "monthly"
|
|
45
|
+
open-pull-requests-limit: 3
|
|
46
|
+
groups:
|
|
47
|
+
all-github-actions:
|
|
48
|
+
patterns: ["*"]
|
|
49
|
+
update-types: ["minor", "patch"]
|
|
50
|
+
|
|
51
|
+
# Daily security-only overlay for actions (CT-B-006).
|
|
52
|
+
- package-ecosystem: "github-actions"
|
|
53
|
+
directory: "/"
|
|
54
|
+
schedule:
|
|
55
|
+
interval: "daily"
|
|
56
|
+
open-pull-requests-limit: 10
|
|
57
|
+
allow:
|
|
58
|
+
- dependency-type: "all"
|
|
59
|
+
labels:
|
|
60
|
+
- "security"
|
|
61
|
+
- "dependencies"
|
|
62
|
+
|
|
63
|
+
# =============================================================================
|
|
64
|
+
# docker — Dockerfile base-image FROM directives (CT-B-005)
|
|
65
|
+
# =============================================================================
|
|
66
|
+
# Pairs with the digest-pinned `FROM python:3.11-slim@sha256:...` in
|
|
67
|
+
# Dockerfile (CT-B-003). Without this ecosystem entry the digest pin
|
|
68
|
+
# would become a stale anchor with no machine-readable refresh path.
|
|
69
|
+
- package-ecosystem: "docker"
|
|
70
|
+
directory: "/"
|
|
71
|
+
schedule:
|
|
72
|
+
interval: "monthly"
|
|
73
|
+
open-pull-requests-limit: 2
|
|
74
|
+
groups:
|
|
75
|
+
all-docker:
|
|
76
|
+
patterns: ["*"]
|
|
77
|
+
update-types: ["minor", "patch"]
|
|
78
|
+
|
|
79
|
+
# Daily security-only overlay for docker base images (CT-B-006).
|
|
80
|
+
- package-ecosystem: "docker"
|
|
81
|
+
directory: "/"
|
|
82
|
+
schedule:
|
|
83
|
+
interval: "daily"
|
|
84
|
+
open-pull-requests-limit: 10
|
|
85
|
+
allow:
|
|
86
|
+
- dependency-type: "all"
|
|
87
|
+
labels:
|
|
88
|
+
- "security"
|
|
89
|
+
- "dependencies"
|
|
@@ -35,9 +35,16 @@ on:
|
|
|
35
35
|
- cron: '0 9 * * 1,3,5'
|
|
36
36
|
workflow_dispatch:
|
|
37
37
|
|
|
38
|
-
concurrency
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
# NOTE: concurrency is intentionally NOT set at the workflow level.
|
|
39
|
+
# A workflow-level cancel-in-progress would cancel the whole run when a
|
|
40
|
+
# new push lands on the same ref — including the pages-deploy job that
|
|
41
|
+
# carries its own concurrency: pages / cancel-in-progress: false. The
|
|
42
|
+
# job-level setting cannot override workflow-level cancellation because
|
|
43
|
+
# the entire run is cancelled before per-job concurrency takes effect.
|
|
44
|
+
# Each test/lint/integration/docker job below carries its own
|
|
45
|
+
# concurrency block scoped to PR refs only (push events on main are
|
|
46
|
+
# never cancelled). The pages-build / pages-deploy jobs keep their
|
|
47
|
+
# dedicated concurrency: pages group with cancel-in-progress: false.
|
|
41
48
|
|
|
42
49
|
# Default least-privilege; individual jobs that need more elevate explicitly.
|
|
43
50
|
permissions:
|
|
@@ -47,6 +54,13 @@ jobs:
|
|
|
47
54
|
lint:
|
|
48
55
|
name: Org URL sanity check
|
|
49
56
|
runs-on: ubuntu-latest
|
|
57
|
+
# CT-B-011: lint is a sub-30-second shell check; 5 min is generous.
|
|
58
|
+
timeout-minutes: 5
|
|
59
|
+
# PR-scoped concurrency: a newer push to the same PR cancels the
|
|
60
|
+
# older run, but pushes to main never cancel themselves.
|
|
61
|
+
concurrency:
|
|
62
|
+
group: lint-${{ github.event.pull_request.number || github.run_id }}
|
|
63
|
+
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
|
|
50
64
|
permissions:
|
|
51
65
|
contents: read
|
|
52
66
|
steps:
|
|
@@ -56,12 +70,27 @@ jobs:
|
|
|
56
70
|
- name: Check for stale org/user URLs
|
|
57
71
|
run: bash scripts/check-org-urls.sh
|
|
58
72
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
73
|
+
- name: Set up Python (pre-commit)
|
|
74
|
+
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
|
|
75
|
+
with:
|
|
76
|
+
python-version: '3.11'
|
|
77
|
+
|
|
78
|
+
# CT-B-018: run the pre-commit hooks (ruff format + ruff check +
|
|
79
|
+
# standard hygiene + gitleaks). Same hooks the contributor runs
|
|
80
|
+
# locally; this is the CI-side enforcement. Soft-fail for the first
|
|
81
|
+
# cycle to surface formatting drift without blocking PRs while
|
|
82
|
+
# contributors install pre-commit locally.
|
|
83
|
+
# TODO(swarm): flip continue-on-error to false after one full release
|
|
84
|
+
# cycle so the pre-commit gate becomes blocking.
|
|
85
|
+
- name: Run pre-commit hooks
|
|
64
86
|
continue-on-error: true
|
|
87
|
+
uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1
|
|
88
|
+
|
|
89
|
+
# CDS-FT-001: SCORECARD drift guard — now BLOCKING. The dogfood-swarm v3
|
|
90
|
+
# pass fixed CIDOCS-01 (regenerate-scorecard.sh forces NO_COLOR + strips
|
|
91
|
+
# ANSI), so `--check` diff-cleans deterministically in non-TTY CI. The
|
|
92
|
+
# committed SCORECARD was verified in sync at flip time.
|
|
93
|
+
- name: Verify SCORECARD is in sync
|
|
65
94
|
run: |
|
|
66
95
|
if [ -f Makefile ] && grep -q "^verify-scorecard:" Makefile; then
|
|
67
96
|
make verify-scorecard
|
|
@@ -69,9 +98,32 @@ jobs:
|
|
|
69
98
|
echo "Makefile verify-scorecard target missing — skipping"
|
|
70
99
|
fi
|
|
71
100
|
|
|
101
|
+
# CT-B-008 cross-domain: verify that /metrics emits the expected
|
|
102
|
+
# Four Golden Signals surface. Soft-fail because the saturation
|
|
103
|
+
# gauges land in BE-B-002 (backend domain); flip to fatal once that
|
|
104
|
+
# work merges.
|
|
105
|
+
- name: Verify metrics surface (Four Golden Signals)
|
|
106
|
+
continue-on-error: true
|
|
107
|
+
run: |
|
|
108
|
+
if [ -f Makefile ] && grep -q "^verify-metrics:" Makefile; then
|
|
109
|
+
python -m pip install --upgrade pip
|
|
110
|
+
pip install -r requirements.txt || true
|
|
111
|
+
make verify-metrics || true
|
|
112
|
+
else
|
|
113
|
+
echo "Makefile verify-metrics target missing — skipping"
|
|
114
|
+
fi
|
|
115
|
+
|
|
72
116
|
test:
|
|
73
117
|
name: Python ${{ matrix.python-version }} on ${{ matrix.os }}
|
|
74
118
|
runs-on: ${{ matrix.os }}
|
|
119
|
+
# CT-B-011: per-matrix-cell budget. pytest has its own 30s per-test cap
|
|
120
|
+
# (pyproject.toml [tool.pytest.ini_options]); 15 min envelope covers
|
|
121
|
+
# install + coverage + pip-audit with headroom for a slow runner.
|
|
122
|
+
timeout-minutes: 15
|
|
123
|
+
# PR-scoped concurrency (see workflow-top NOTE).
|
|
124
|
+
concurrency:
|
|
125
|
+
group: test-${{ matrix.python-version }}-${{ github.event.pull_request.number || github.run_id }}
|
|
126
|
+
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
|
|
75
127
|
permissions:
|
|
76
128
|
contents: read
|
|
77
129
|
|
|
@@ -116,6 +168,9 @@ jobs:
|
|
|
116
168
|
name: junit-reports-${{ matrix.python-version }}
|
|
117
169
|
path: junit-${{ matrix.python-version }}.xml
|
|
118
170
|
if-no-files-found: warn
|
|
171
|
+
# CT-B-012: JUnit reports are short-lived diagnostic data — only
|
|
172
|
+
# useful for the most recent few runs. Default 90d is wasted.
|
|
173
|
+
retention-days: 14
|
|
119
174
|
|
|
120
175
|
- name: Run tests with coverage
|
|
121
176
|
if: matrix.python-version == '3.11' && matrix.os == 'ubuntu-latest'
|
|
@@ -142,13 +197,17 @@ jobs:
|
|
|
142
197
|
name: pip-audit-report
|
|
143
198
|
path: pip-audit-report.json
|
|
144
199
|
if-no-files-found: ignore
|
|
200
|
+
# CT-B-012: CVE diagnostic snapshot — 14d aligns with the JUnit
|
|
201
|
+
# retention and is plenty of window for incident response.
|
|
202
|
+
retention-days: 14
|
|
145
203
|
|
|
204
|
+
# Now BLOCKING. The dogfood-swarm v3 pass reviewed the CVE baseline:
|
|
205
|
+
# `pip-audit -r requirements.txt` reports no known vulnerabilities. The
|
|
206
|
+
# report-only artifact step above still runs for the full JSON snapshot.
|
|
146
207
|
- name: Audit dependencies for vulnerabilities
|
|
147
208
|
if: matrix.python-version == '3.11' && matrix.os == 'ubuntu-latest'
|
|
148
209
|
run: |
|
|
149
210
|
pip-audit -r requirements.txt
|
|
150
|
-
# TODO(swarm): enforce after CVE baseline reviewed — issue #TBD
|
|
151
|
-
continue-on-error: true # Warn-only until clean baseline established
|
|
152
211
|
|
|
153
212
|
# TST-FT-002: nightly Hypothesis fuzzing. Runs on schedule (Mon/Wed/Fri 09:00
|
|
154
213
|
# UTC) or manually via workflow_dispatch. Never runs on push/PR — nightly-only.
|
|
@@ -157,6 +216,9 @@ jobs:
|
|
|
157
216
|
name: Nightly Hypothesis fuzz
|
|
158
217
|
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
|
|
159
218
|
runs-on: ubuntu-latest
|
|
219
|
+
# CT-B-011: Hypothesis nightly profile is deliberately slow — 45 min cap
|
|
220
|
+
# is wider than the test job because fuzz examples are unbounded.
|
|
221
|
+
timeout-minutes: 45
|
|
160
222
|
permissions:
|
|
161
223
|
contents: read
|
|
162
224
|
issues: write
|
|
@@ -184,9 +246,10 @@ jobs:
|
|
|
184
246
|
|
|
185
247
|
- name: Open tracking issue on failure
|
|
186
248
|
if: failure() && steps.fuzz.conclusion == 'failure'
|
|
187
|
-
#
|
|
188
|
-
#
|
|
189
|
-
|
|
249
|
+
# SHA-pinned per SLSA L3 supply-chain hygiene (CT-B-001). nightly-fuzz
|
|
250
|
+
# carries issues:write, so a compromised v7 mutable tag would inherit
|
|
251
|
+
# issue-creation capability. Bump via dependabot's github-actions sweep.
|
|
252
|
+
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
|
190
253
|
with:
|
|
191
254
|
script: |
|
|
192
255
|
const title = `[nightly-fuzz] Hypothesis failures on ${context.sha}`;
|
|
@@ -212,6 +275,13 @@ jobs:
|
|
|
212
275
|
name: Integration Tests
|
|
213
276
|
runs-on: ubuntu-latest
|
|
214
277
|
needs: test # Only run after unit tests pass
|
|
278
|
+
# CT-B-011: Ollama install + nomic-embed-text pull + integration suite
|
|
279
|
+
# dominates; 25 min envelope covers the cold-start pull path.
|
|
280
|
+
timeout-minutes: 25
|
|
281
|
+
# PR-scoped concurrency (see workflow-top NOTE).
|
|
282
|
+
concurrency:
|
|
283
|
+
group: integration-${{ github.event.pull_request.number || github.run_id }}
|
|
284
|
+
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
|
|
215
285
|
permissions:
|
|
216
286
|
contents: read
|
|
217
287
|
|
|
@@ -271,6 +341,12 @@ jobs:
|
|
|
271
341
|
name: Docker Build
|
|
272
342
|
runs-on: ubuntu-latest
|
|
273
343
|
needs: test
|
|
344
|
+
# CT-B-011: docker buildx + gha cache; 20 min covers a cold-cache build.
|
|
345
|
+
timeout-minutes: 20
|
|
346
|
+
# PR-scoped concurrency (see workflow-top NOTE).
|
|
347
|
+
concurrency:
|
|
348
|
+
group: docker-${{ github.event.pull_request.number || github.run_id }}
|
|
349
|
+
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
|
|
274
350
|
permissions:
|
|
275
351
|
contents: read
|
|
276
352
|
|
|
@@ -299,6 +375,8 @@ jobs:
|
|
|
299
375
|
name: Build site
|
|
300
376
|
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
|
|
301
377
|
runs-on: ubuntu-latest
|
|
378
|
+
# CT-B-011: Starlight npm ci + Astro build; 10 min is generous.
|
|
379
|
+
timeout-minutes: 10
|
|
302
380
|
permissions:
|
|
303
381
|
contents: read
|
|
304
382
|
steps:
|
|
@@ -308,6 +386,12 @@ jobs:
|
|
|
308
386
|
with:
|
|
309
387
|
node-version: 22
|
|
310
388
|
|
|
389
|
+
# CT-B-016: read repo-level Pages configuration so the build is not
|
|
390
|
+
# silently dependent on Settings → Pages UI state. configure-pages
|
|
391
|
+
# is idempotent and exposes the base path to downstream steps.
|
|
392
|
+
- name: Configure Pages
|
|
393
|
+
uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0
|
|
394
|
+
|
|
311
395
|
- name: Install site dependencies
|
|
312
396
|
working-directory: site
|
|
313
397
|
run: npm ci
|
|
@@ -325,6 +409,9 @@ jobs:
|
|
|
325
409
|
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
|
|
326
410
|
needs: pages-build
|
|
327
411
|
runs-on: ubuntu-latest
|
|
412
|
+
# CT-B-011: deploy is a metadata operation against the Pages backend;
|
|
413
|
+
# 5 min is the fail-fast budget.
|
|
414
|
+
timeout-minutes: 5
|
|
328
415
|
# Dedicated concurrency group so a long deploy is never cancelled by a
|
|
329
416
|
# newer CI run (CDS-A-012).
|
|
330
417
|
concurrency:
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
# Tool Compass Release Pipeline
|
|
2
|
+
# Publishes to PyPI (trusted publishing) and GHCR on release
|
|
3
|
+
|
|
4
|
+
name: Publish
|
|
5
|
+
|
|
6
|
+
# Triggers — the load-bearing one for the auto-chain is `workflow_run`:
|
|
7
|
+
# * `release: published` does NOT fire when the Release was created by
|
|
8
|
+
# release.yml using secrets.GITHUB_TOKEN (GitHub's recursion guard). Without
|
|
9
|
+
# the workflow_run trigger below, a tag-push release would publish to npm
|
|
10
|
+
# (via release.yml) but silently SKIP PyPI + GHCR here. The `workflow_run`
|
|
11
|
+
# trigger gated on Release.conclusion == 'success' closes the chain.
|
|
12
|
+
# * `release: published` retained for manual hand-cut Releases (gh release
|
|
13
|
+
# create from a maintainer's terminal — attributed to a user, fires normally).
|
|
14
|
+
# * `workflow_dispatch` retained for re-run-from-UI on transient failure.
|
|
15
|
+
on:
|
|
16
|
+
release:
|
|
17
|
+
types: [published]
|
|
18
|
+
workflow_run:
|
|
19
|
+
workflows: [Release]
|
|
20
|
+
types: [completed]
|
|
21
|
+
workflow_dispatch:
|
|
22
|
+
|
|
23
|
+
# Publish workflows must serialize, not cancel. Cancelling a mid-flight twine
|
|
24
|
+
# upload leaves PyPI in a state where the next retry fails with E409 ('File
|
|
25
|
+
# already exists') and needs manual --skip-existing recovery. Group per release
|
|
26
|
+
# tag — resolved across all trigger types (under workflow_run github.ref is the
|
|
27
|
+
# default branch, not the tag) — so distinct tags run independently while
|
|
28
|
+
# same-tag re-fires queue safely.
|
|
29
|
+
concurrency:
|
|
30
|
+
group: ${{ github.workflow }}-${{ github.event.workflow_run.head_branch || github.event.release.tag_name || github.ref }}
|
|
31
|
+
cancel-in-progress: false
|
|
32
|
+
|
|
33
|
+
env:
|
|
34
|
+
REGISTRY: ghcr.io
|
|
35
|
+
IMAGE_NAME: ${{ github.repository }}
|
|
36
|
+
|
|
37
|
+
jobs:
|
|
38
|
+
build:
|
|
39
|
+
name: Build package
|
|
40
|
+
runs-on: ubuntu-latest
|
|
41
|
+
# When triggered by workflow_run, only proceed if the upstream Release
|
|
42
|
+
# workflow succeeded. release: published / workflow_dispatch invocations set
|
|
43
|
+
# workflow_run to null, which evaluates this expression to truthy (we only
|
|
44
|
+
# want to short-circuit FAILED workflow_run events).
|
|
45
|
+
if: ${{ github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success' }}
|
|
46
|
+
# CT-B-011: fail-fast budgets per SRE 'fail fast' (Google SRE Book ch.21).
|
|
47
|
+
# Default GitHub timeout is 360 min; a wedged dependency install or twine
|
|
48
|
+
# check is well outside the legitimate envelope at 10 min.
|
|
49
|
+
timeout-minutes: 10
|
|
50
|
+
|
|
51
|
+
steps:
|
|
52
|
+
- name: Checkout repository
|
|
53
|
+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
|
54
|
+
with:
|
|
55
|
+
# Under workflow_run, github.ref is the default branch (main), NOT the
|
|
56
|
+
# tag — build the tagged commit, not main's HEAD. Resolve the tag from
|
|
57
|
+
# the single canonical expression used throughout this workflow.
|
|
58
|
+
ref: ${{ github.event.workflow_run.head_branch || github.event.release.tag_name || github.ref_name }}
|
|
59
|
+
|
|
60
|
+
- name: Set up Python
|
|
61
|
+
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
|
|
62
|
+
with:
|
|
63
|
+
python-version: '3.11'
|
|
64
|
+
|
|
65
|
+
- name: Install build tools
|
|
66
|
+
run: |
|
|
67
|
+
python -m pip install --upgrade pip
|
|
68
|
+
pip install build twine
|
|
69
|
+
|
|
70
|
+
- name: Build package
|
|
71
|
+
run: python -m build
|
|
72
|
+
|
|
73
|
+
- name: Check package with twine
|
|
74
|
+
run: twine check dist/*
|
|
75
|
+
|
|
76
|
+
- name: Upload build artifacts
|
|
77
|
+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
|
78
|
+
with:
|
|
79
|
+
name: dist
|
|
80
|
+
path: dist/
|
|
81
|
+
# CT-B-012: dist/ is an ephemeral build-to-publish handoff; the
|
|
82
|
+
# canonical artifacts live at PyPI + GHCR after publish completes.
|
|
83
|
+
# Keep the workflow copy around 7 days for incident-response replays.
|
|
84
|
+
retention-days: 7
|
|
85
|
+
|
|
86
|
+
publish-pypi:
|
|
87
|
+
name: Publish to PyPI
|
|
88
|
+
runs-on: ubuntu-latest
|
|
89
|
+
needs: build
|
|
90
|
+
environment: pypi
|
|
91
|
+
# CT-B-011: PyPI upload + propagation; 10 min covers retries.
|
|
92
|
+
timeout-minutes: 10
|
|
93
|
+
permissions:
|
|
94
|
+
id-token: write
|
|
95
|
+
# CT-B-009: attestations:write enables SLSA provenance attestations on
|
|
96
|
+
# the published wheel + sdist via pypa/gh-action-pypi-publish v1.13+.
|
|
97
|
+
# Combined with `attestations: true` below, PyPI surfaces a verifiable
|
|
98
|
+
# build attestation tied to this commit + workflow run.
|
|
99
|
+
attestations: write
|
|
100
|
+
contents: read
|
|
101
|
+
|
|
102
|
+
steps:
|
|
103
|
+
- name: Download build artifacts
|
|
104
|
+
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
|
105
|
+
with:
|
|
106
|
+
name: dist
|
|
107
|
+
path: dist/
|
|
108
|
+
|
|
109
|
+
- name: Publish to PyPI
|
|
110
|
+
uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # v1.14.0
|
|
111
|
+
with:
|
|
112
|
+
# CT-B-009: emit SLSA build provenance attestations for the wheel
|
|
113
|
+
# and sdist. PyPI verifies the attestation against the workflow's
|
|
114
|
+
# OIDC identity; downstream consumers can audit the chain from a
|
|
115
|
+
# specific commit -> workflow run -> published artifact.
|
|
116
|
+
attestations: true
|
|
117
|
+
|
|
118
|
+
docker:
|
|
119
|
+
name: Publish to GHCR
|
|
120
|
+
runs-on: ubuntu-latest
|
|
121
|
+
# PyPI ships first (CDS-B-005). If PyPI fails, Docker must not ship a
|
|
122
|
+
# half-release; if PyPI succeeds, Docker becomes the recoverable tail.
|
|
123
|
+
needs: publish-pypi
|
|
124
|
+
# CT-B-011: multi-arch buildx (linux/amd64 + linux/arm64) + push to GHCR
|
|
125
|
+
# is the longest leg; 30 min covers the warm cache path with headroom.
|
|
126
|
+
timeout-minutes: 30
|
|
127
|
+
permissions:
|
|
128
|
+
contents: read
|
|
129
|
+
packages: write
|
|
130
|
+
# CT-B-009: id-token + attestations enable buildx SLSA provenance
|
|
131
|
+
# mode=max on the image manifest below.
|
|
132
|
+
id-token: write
|
|
133
|
+
attestations: write
|
|
134
|
+
|
|
135
|
+
steps:
|
|
136
|
+
- name: Checkout repository
|
|
137
|
+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
|
138
|
+
with:
|
|
139
|
+
# Under workflow_run, github.ref is main, NOT the tag — build the
|
|
140
|
+
# tagged commit, not main's HEAD. Same resolved-tag expression used
|
|
141
|
+
# throughout this workflow.
|
|
142
|
+
ref: ${{ github.event.workflow_run.head_branch || github.event.release.tag_name || github.ref_name }}
|
|
143
|
+
|
|
144
|
+
- name: Log in to GHCR
|
|
145
|
+
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
|
|
146
|
+
with:
|
|
147
|
+
registry: ${{ env.REGISTRY }}
|
|
148
|
+
username: ${{ github.actor }}
|
|
149
|
+
password: ${{ secrets.GITHUB_TOKEN }}
|
|
150
|
+
|
|
151
|
+
# Resolve the release version explicitly. Under workflow_run github.ref
|
|
152
|
+
# points at the default branch (main), NOT the tag — so
|
|
153
|
+
# docker/metadata-action's type=semver rules (which only fire on a
|
|
154
|
+
# refs/tags/... ref) emit NOTHING and the image never gets a :X.Y.Z / :X.Y
|
|
155
|
+
# tag (only :latest + :sha-...). The tag that started the upstream Release
|
|
156
|
+
# run is carried on github.event.workflow_run.head_branch (= the tag ref).
|
|
157
|
+
# Feed the resolved version into metadata-action via type=raw below.
|
|
158
|
+
- name: Resolve release version
|
|
159
|
+
id: ver
|
|
160
|
+
shell: bash
|
|
161
|
+
run: |
|
|
162
|
+
set -euo pipefail
|
|
163
|
+
REF="${{ github.event.workflow_run.head_branch || github.event.release.tag_name || github.ref_name }}"
|
|
164
|
+
V="${REF#v}"
|
|
165
|
+
echo "version=${V}" >> "$GITHUB_OUTPUT"
|
|
166
|
+
echo "major_minor=$(echo "$V" | cut -d. -f1-2)" >> "$GITHUB_OUTPUT"
|
|
167
|
+
echo "resolved=${V} (event=${{ github.event_name }} ref=${REF})"
|
|
168
|
+
|
|
169
|
+
- name: Extract metadata
|
|
170
|
+
id: meta
|
|
171
|
+
uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0
|
|
172
|
+
with:
|
|
173
|
+
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
|
174
|
+
# type=raw from the explicitly-resolved version (see Resolve step) —
|
|
175
|
+
# NOT type=semver, which silently emits nothing under workflow_run
|
|
176
|
+
# because github.ref is main, not the tag. Each enable=... gates its
|
|
177
|
+
# raw tag so an empty/missing version never pushes a bogus tag.
|
|
178
|
+
tags: |
|
|
179
|
+
type=raw,value=${{ steps.ver.outputs.version }},enable=${{ steps.ver.outputs.version != '' }}
|
|
180
|
+
type=raw,value=${{ steps.ver.outputs.major_minor }},enable=${{ steps.ver.outputs.major_minor != '' }}
|
|
181
|
+
type=sha
|
|
182
|
+
type=raw,value=latest,enable={{is_default_branch}}
|
|
183
|
+
|
|
184
|
+
# QEMU is required to cross-build linux/arm64 from an amd64 runner.
|
|
185
|
+
- name: Set up QEMU
|
|
186
|
+
# SHA-pinned per SLSA L3 supply-chain hygiene (CT-B-002). publish job
|
|
187
|
+
# carries packages:write — a compromised mutable v3 tag would inherit
|
|
188
|
+
# GHCR write capability during a release window. Bump via dependabot.
|
|
189
|
+
uses: docker/setup-qemu-action@06116385d9baf250c9f4dcb4858b16962ea869c3 # v4.1.0
|
|
190
|
+
|
|
191
|
+
- name: Set up Docker Buildx
|
|
192
|
+
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
|
|
193
|
+
|
|
194
|
+
- name: Build and push
|
|
195
|
+
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
|
|
196
|
+
with:
|
|
197
|
+
context: .
|
|
198
|
+
push: true
|
|
199
|
+
platforms: linux/amd64,linux/arm64
|
|
200
|
+
tags: ${{ steps.meta.outputs.tags }}
|
|
201
|
+
labels: ${{ steps.meta.outputs.labels }}
|
|
202
|
+
cache-from: type=gha
|
|
203
|
+
cache-to: type=gha,mode=max
|
|
204
|
+
# CT-B-009: SLSA provenance mode=max emits buildx provenance
|
|
205
|
+
# attestation (including all input source digests) attached to the
|
|
206
|
+
# image manifest. sbom: true emits an SPDX SBOM attestation in the
|
|
207
|
+
# same manifest. Both consumable via `cosign verify-attestation`
|
|
208
|
+
# or `docker buildx imagetools inspect`.
|
|
209
|
+
provenance: mode=max
|
|
210
|
+
sbom: true
|
|
211
|
+
|
|
212
|
+
release-smoke:
|
|
213
|
+
name: Release smoke test
|
|
214
|
+
runs-on: ubuntu-latest
|
|
215
|
+
needs: [publish-pypi, docker]
|
|
216
|
+
# CT-B-011: PyPI propagation retry loop + docker pull + version handshake.
|
|
217
|
+
# 15 min is the propagation-retry window plus headroom.
|
|
218
|
+
timeout-minutes: 15
|
|
219
|
+
permissions:
|
|
220
|
+
contents: read
|
|
221
|
+
packages: read
|
|
222
|
+
steps:
|
|
223
|
+
- name: Derive version (strip leading v)
|
|
224
|
+
id: ver
|
|
225
|
+
run: |
|
|
226
|
+
set -euo pipefail
|
|
227
|
+
# Resolve the tag across all trigger types. Under workflow_run
|
|
228
|
+
# github.event.release.tag_name is null and github.ref is main —
|
|
229
|
+
# workflow_run.head_branch carries the tag ref (e.g. v2.4.0).
|
|
230
|
+
TAG="${{ github.event.workflow_run.head_branch || github.event.release.tag_name || github.ref_name }}"
|
|
231
|
+
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
|
|
232
|
+
echo "version=${TAG#v}" >> "$GITHUB_OUTPUT"
|
|
233
|
+
|
|
234
|
+
- name: Set up Python
|
|
235
|
+
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
|
|
236
|
+
with:
|
|
237
|
+
python-version: '3.11'
|
|
238
|
+
|
|
239
|
+
- name: PyPI smoke — install + --version matches tag
|
|
240
|
+
run: |
|
|
241
|
+
set -euo pipefail
|
|
242
|
+
VERSION="${{ steps.ver.outputs.version }}"
|
|
243
|
+
# PyPI propagation is fast but not instant; retry briefly. If no
|
|
244
|
+
# iteration succeeds the loop falls through and the subsequent
|
|
245
|
+
# `tool-compass --version` invocation fails with a clear "command
|
|
246
|
+
# not found", which is the desired loud failure mode (CT-B-014).
|
|
247
|
+
install_ok=0
|
|
248
|
+
for _ in $(seq 1 12); do
|
|
249
|
+
if pip install "tool-compass==${VERSION}"; then
|
|
250
|
+
install_ok=1
|
|
251
|
+
break
|
|
252
|
+
fi
|
|
253
|
+
sleep 10
|
|
254
|
+
done
|
|
255
|
+
if [ "$install_ok" -ne 1 ]; then
|
|
256
|
+
echo "::error::PyPI smoke failed: tool-compass==${VERSION} did not become installable in the propagation window"
|
|
257
|
+
exit 1
|
|
258
|
+
fi
|
|
259
|
+
OUT="$(tool-compass --version 2>&1 || true)"
|
|
260
|
+
echo "tool-compass --version → $OUT"
|
|
261
|
+
echo "$OUT" | grep -Fq "${VERSION}" || {
|
|
262
|
+
echo "::error::PyPI smoke failed: --version output did not contain ${VERSION}"
|
|
263
|
+
exit 1
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
- name: Log in to GHCR (pull)
|
|
267
|
+
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
|
|
268
|
+
with:
|
|
269
|
+
registry: ${{ env.REGISTRY }}
|
|
270
|
+
username: ${{ github.actor }}
|
|
271
|
+
password: ${{ secrets.GITHUB_TOKEN }}
|
|
272
|
+
|
|
273
|
+
- name: Docker smoke — pull + --version matches tag
|
|
274
|
+
run: |
|
|
275
|
+
set -euo pipefail
|
|
276
|
+
TAG="${{ steps.ver.outputs.tag }}"
|
|
277
|
+
VERSION="${{ steps.ver.outputs.version }}"
|
|
278
|
+
IMAGE="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${VERSION}"
|
|
279
|
+
docker pull "$IMAGE"
|
|
280
|
+
OUT="$(docker run --rm --entrypoint tool-compass "$IMAGE" --version 2>&1 || true)"
|
|
281
|
+
echo "docker --version → $OUT"
|
|
282
|
+
echo "$OUT" | grep -Fq "${VERSION}" || {
|
|
283
|
+
echo "::error::Docker smoke failed: --version output did not contain ${VERSION}"
|
|
284
|
+
exit 1
|
|
285
|
+
}
|