Repository navigation
157 lines (152 loc) · 7.34 KB
/
Copy pathci.yml
File metadata and controls
157 lines (152 loc) · 7.34 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
permissions:
contents: read
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: '3.11'
- name: Install dependencies
run: pip install -e '.[dev]'
- name: Lint (Makefile lint target)
# Wire the repo Makefile lint target into CI: ruff check over tools/.
run: make lint
- name: consumer boundary guard
run: bash ./scripts/check-consumer-boundaries.sh
- name: Compile category payload scripts
# Syntax-check shipped skill scripts so a SyntaxError in
# categories/**/scripts/*.py fails the build (they are never imported
# by the test suite).
run: python3 -m compileall -q categories
- name: Correctness and TLS-safety ratchet for changed scripts
env:
BASE_REF: ${{ github.event.pull_request.base.sha || github.event.before }}
run: |
# github.event.before is all zeros for a new branch or a force-push,
# and may be missing from history; fall back to the parent commit.
if [ -z "$BASE_REF" ] || ! git cat-file -e "${BASE_REF}^{commit}" 2>/dev/null; then
BASE_REF="$(git rev-parse HEAD~1)"
fi
mapfile -t changed < <(git diff --name-only "$BASE_REF" HEAD)
python3 tools/check_changed_scripts.py "${changed[@]}"
- name: Validate all skills
run: >-
python3 tools/validate_skill.py --all
--warning-budget tools/validation_warning_budget.json
- name: Registry build (schema and duplicate-name check)
# registry.json is generated, not committed, so there is no drift to
# detect here. Building it fails on duplicate skill names and on any
# entry that violates tools/registry_schema.py.
run: python3 tools/update_registry.py
- name: Version sync check
run: python3 tools/check_version_sync.py
- name: Marketplace sync check
# Fail if .claude-plugin/marketplace.json is stale vs categories/.
# Regenerate with: python3 tools/sync_marketplace.py
run: python3 tools/sync_marketplace.py --check
- name: Reference integrity
run: python3 tools/check_references.py
- name: Self-containment check
run: python3 tools/check_self_contained.py
- name: License compatibility gate
# Copyleft (GPL/LGPL/AGPL) content must not be vendored into the
# MIT-rooted repo, in LICENSE files or frontmatter. See NOTICE.
run: python3 tools/check_licenses.py
- name: Agent Skills conformance (first-party skills)
# GrayCode's own skills must follow agentskills.io exactly; the
# legacy corpus gap is reported by --all (see docs/AGENT_SKILLS.md).
run: python3 tools/check_agentskills.py --strict categories/graycode
- name: Run tests
run: python -m pytest tests/ -v --cov --cov-report=term-missing --cov-fail-under=88
- name: Packaging smoke check
run: make package-check
- name: Security audit
run: python3 tools/check_secrets.py --strict
- name: Shell-command audit
run: python3 tools/check_shell_commands.py --strict
- name: Dependency security audit
run: pip-audit -r tools/requirements.txt
- name: Dependency security audit (publish lock files)
# The hash-locked sets publish-registry.yml installs, including the
# signing job's cryptography stack.
run: pip-audit --require-hashes -r tools/requirements.lock -r tools/requirements-sign.lock
# -------------------------------------------------------------------------
# Sandbox containment check for changed skill scripts. Deliberately scoped
# to changed files only (mirrors the ratchet job above) — see
# tools/sandbox_run_changed_scripts.py's module docstring for exactly what
# this does and does not prove: it checks that network/filesystem/
# resource isolation actually holds when a changed script is invoked with
# --help, not that the script's real business logic (which routinely
# needs cloud credentials, live network targets, or external binaries
# this CI must never provide) is safe or correct.
# -------------------------------------------------------------------------
sandbox:
name: sandbox (changed scripts containment check)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: '3.11'
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0
- name: Build sandbox image
# Built fresh (with layer caching) rather than pulled from a
# previously-published tag, so the sandbox always matches this
# exact commit's Dockerfile.sandbox / sandbox_requirements.txt —
# no version-skew risk between what's tested and what's pushed.
uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0
with:
context: .
file: Dockerfile.sandbox
tags: graycode-skills-sandbox:ci
push: false
load: true
cache-from: type=gha,scope=sandbox
cache-to: type=gha,mode=max,scope=sandbox
- name: Sandbox-test changed scripts
env:
BASE_REF: ${{ github.event.pull_request.base.sha || github.event.before }}
run: |
# Same zero-SHA / force-push guard as the validate job.
if [ -z "$BASE_REF" ] || ! git cat-file -e "${BASE_REF}^{commit}" 2>/dev/null; then
BASE_REF="$(git rev-parse HEAD~1)"
fi
mapfile -t changed < <(git diff --name-only "$BASE_REF" HEAD)
python3 tools/sandbox_run_changed_scripts.py --image graycode-skills-sandbox:ci "${changed[@]}"
# -------------------------------------------------------------------------
# Duplication detection — jscpd (scan categories with reasonable thresholds).
# -------------------------------------------------------------------------
jscpd:
name: duplication
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: '20'
- name: jscpd
# An enforced ceiling. This step used to pipe into `tail` without
# pipefail, so `--threshold 5` never failed the job: main reported
# "found too many duplicates (9.3%) over threshold (5.0%)" and still
# passed. jscpd 5.3.2 measures 11.4% duplicated lines on 2026-09-27,
# mostly in ingested prompt collections. Lower the ceiling as
# duplication is removed; never raise it. The version is pinned
# because percentages differ between jscpd releases.
shell: bash
run: |
set -o pipefail
npx --yes jscpd@5.3.2 --min-lines 15 --min-tokens 150 --threshold 12 --reporters console \
--ignore "docs/**,plans/**,tools/**" . 2>&1 | tail -30