code2okf 0.1.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.
- code2okf-0.1.0/.coderabbit.yaml +168 -0
- code2okf-0.1.0/.cspell.json +103 -0
- code2okf-0.1.0/.editorconfig +13 -0
- code2okf-0.1.0/.github/workflows/ci.yml +184 -0
- code2okf-0.1.0/.github/workflows/release.yml +209 -0
- code2okf-0.1.0/.gitignore +25 -0
- code2okf-0.1.0/.markdownlint-cli2.yaml +9 -0
- code2okf-0.1.0/.mcp.json +23 -0
- code2okf-0.1.0/.python-version +1 -0
- code2okf-0.1.0/.shellcheckrc +34 -0
- code2okf-0.1.0/.vscode/extensions.json +5 -0
- code2okf-0.1.0/.vscode/mcp.json +16 -0
- code2okf-0.1.0/.vscode/settings.json +3 -0
- code2okf-0.1.0/.yamllint +10 -0
- code2okf-0.1.0/AGENTS.md +177 -0
- code2okf-0.1.0/CHANGELOG.md +95 -0
- code2okf-0.1.0/CLAUDE.md +1 -0
- code2okf-0.1.0/CONTRIBUTING.md +216 -0
- code2okf-0.1.0/LICENSE +21 -0
- code2okf-0.1.0/LICENSE-OKF-SPEC.txt +203 -0
- code2okf-0.1.0/Makefile +166 -0
- code2okf-0.1.0/NOTICE-OKF-SPEC.md +37 -0
- code2okf-0.1.0/PKG-INFO +391 -0
- code2okf-0.1.0/README.md +368 -0
- code2okf-0.1.0/SPEC.md +1006 -0
- code2okf-0.1.0/VERSION +1 -0
- code2okf-0.1.0/kits/code2okf/README.md +128 -0
- code2okf-0.1.0/kits/code2okf/files/home/.local/lib/code2okf/mount-state.sh +48 -0
- code2okf-0.1.0/kits/code2okf/files/home/.pi/agent/AGENTS.md +185 -0
- code2okf-0.1.0/kits/code2okf/files/home/.pi/agent/models.json +84 -0
- code2okf-0.1.0/kits/code2okf/files/home/.pi/agent/settings.json +7 -0
- code2okf-0.1.0/kits/code2okf/files/home/.pi/agent/skills/compile-okf/SKILL.md +142 -0
- code2okf-0.1.0/kits/code2okf/files/home/.pi/agent/skills/compile-okf/scripts/check-okf.sh +155 -0
- code2okf-0.1.0/kits/code2okf/files/home/.pi/agent/skills/compile-okf/scripts/frontmatter-guard.py +289 -0
- code2okf-0.1.0/kits/code2okf/files/home/.pi/agent/skills/curate-okf/SKILL.md +68 -0
- code2okf-0.1.0/kits/code2okf/files/home/.pi/agent/skills/inspect-md/SKILL.md +52 -0
- code2okf-0.1.0/kits/code2okf/files/home/.pi/agent/skills/inspect-okf/SKILL.md +47 -0
- code2okf-0.1.0/kits/code2okf/files/home/.pi/agent/skills/merkle-okf/SKILL.md +59 -0
- code2okf-0.1.0/kits/code2okf/files/home/.pi/agent/skills/size-okf/SKILL.md +52 -0
- code2okf-0.1.0/kits/code2okf/spec.yaml +312 -0
- code2okf-0.1.0/md/.gitkeep +0 -0
- code2okf-0.1.0/md/GoogleStyleGuide-abridged.md +2505 -0
- code2okf-0.1.0/pdf2md/README.md +71 -0
- code2okf-0.1.0/pdf2md/pyproject.toml +11 -0
- code2okf-0.1.0/pdf2md/uv.lock +2148 -0
- code2okf-0.1.0/pyproject.toml +118 -0
- code2okf-0.1.0/scripts/check-release-tag.sh +52 -0
- code2okf-0.1.0/scripts/inspectmd/README.md +42 -0
- code2okf-0.1.0/scripts/inspectmd/pyproject.toml +40 -0
- code2okf-0.1.0/scripts/inspectmd/src/inspectmd/__init__.py +8 -0
- code2okf-0.1.0/scripts/inspectmd/src/inspectmd/__main__.py +5 -0
- code2okf-0.1.0/scripts/inspectmd/src/inspectmd/cli.py +159 -0
- code2okf-0.1.0/scripts/inspectmd/src/inspectmd/parse.py +212 -0
- code2okf-0.1.0/scripts/inspectmd/tests/test_cli.py +108 -0
- code2okf-0.1.0/scripts/inspectmd/tests/test_parse.py +142 -0
- code2okf-0.1.0/scripts/inspectmd/uv.lock +79 -0
- code2okf-0.1.0/scripts/inspectokf/README.md +46 -0
- code2okf-0.1.0/scripts/inspectokf/pyproject.toml +40 -0
- code2okf-0.1.0/scripts/inspectokf/src/inspectokf/__init__.py +8 -0
- code2okf-0.1.0/scripts/inspectokf/src/inspectokf/__main__.py +5 -0
- code2okf-0.1.0/scripts/inspectokf/src/inspectokf/cli.py +104 -0
- code2okf-0.1.0/scripts/inspectokf/tests/test_cli.py +149 -0
- code2okf-0.1.0/scripts/inspectokf/uv.lock +79 -0
- code2okf-0.1.0/scripts/merkleokf/README.md +102 -0
- code2okf-0.1.0/scripts/merkleokf/pyproject.toml +40 -0
- code2okf-0.1.0/scripts/merkleokf/src/merkleokf/__init__.py +8 -0
- code2okf-0.1.0/scripts/merkleokf/src/merkleokf/__main__.py +5 -0
- code2okf-0.1.0/scripts/merkleokf/src/merkleokf/cli.py +121 -0
- code2okf-0.1.0/scripts/merkleokf/src/merkleokf/merkle.py +145 -0
- code2okf-0.1.0/scripts/merkleokf/tests/test_cli.py +168 -0
- code2okf-0.1.0/scripts/merkleokf/tests/test_merkle.py +185 -0
- code2okf-0.1.0/scripts/merkleokf/uv.lock +79 -0
- code2okf-0.1.0/scripts/release-notes.sh +59 -0
- code2okf-0.1.0/scripts/sizeokf/README.md +94 -0
- code2okf-0.1.0/scripts/sizeokf/pyproject.toml +40 -0
- code2okf-0.1.0/scripts/sizeokf/src/sizeokf/__init__.py +8 -0
- code2okf-0.1.0/scripts/sizeokf/src/sizeokf/__main__.py +5 -0
- code2okf-0.1.0/scripts/sizeokf/src/sizeokf/cli.py +93 -0
- code2okf-0.1.0/scripts/sizeokf/src/sizeokf/sizes.py +155 -0
- code2okf-0.1.0/scripts/sizeokf/tests/test_cli.py +134 -0
- code2okf-0.1.0/scripts/sizeokf/tests/test_sizes.py +203 -0
- code2okf-0.1.0/scripts/sizeokf/uv.lock +79 -0
- code2okf-0.1.0/scripts/sync-descriptions.py +169 -0
- code2okf-0.1.0/scripts/validate-spec.sh +23 -0
- code2okf-0.1.0/src/code2okf/__init__.py +8 -0
- code2okf-0.1.0/src/code2okf/cli.py +234 -0
- code2okf-0.1.0/src/code2okf/compile.py +267 -0
- code2okf-0.1.0/src/code2okf/events.py +86 -0
- code2okf-0.1.0/src/code2okf/resources.py +74 -0
- code2okf-0.1.0/src/code2okf/sandbox.py +266 -0
- code2okf-0.1.0/src/code2okf/workbench.py +572 -0
- code2okf-0.1.0/tests/conftest.py +207 -0
- code2okf-0.1.0/tests/test-mount-state.sh +216 -0
- code2okf-0.1.0/tests/test-sandbox-guest.sh +362 -0
- code2okf-0.1.0/tests/test-sandbox.sh +41 -0
- code2okf-0.1.0/tests/test_cli.py +334 -0
- code2okf-0.1.0/tests/test_compile.py +483 -0
- code2okf-0.1.0/tests/test_events.py +92 -0
- code2okf-0.1.0/tests/test_kit.py +37 -0
- code2okf-0.1.0/tests/test_package.py +86 -0
- code2okf-0.1.0/tests/test_resources.py +57 -0
- code2okf-0.1.0/tests/test_sandbox.py +263 -0
- code2okf-0.1.0/tests/test_workbench.py +701 -0
- code2okf-0.1.0/uv.lock +78 -0
- code2okf-0.1.0/web2md/README.md +94 -0
- code2okf-0.1.0/web2md/pyproject.toml +44 -0
- code2okf-0.1.0/web2md/src/web2md.py +768 -0
- code2okf-0.1.0/web2md/tests/conftest.py +98 -0
- code2okf-0.1.0/web2md/tests/test_assemble.py +103 -0
- code2okf-0.1.0/web2md/tests/test_cleaning.py +182 -0
- code2okf-0.1.0/web2md/tests/test_cli.py +69 -0
- code2okf-0.1.0/web2md/tests/test_constants.py +98 -0
- code2okf-0.1.0/web2md/tests/test_converter.py +123 -0
- code2okf-0.1.0/web2md/tests/test_discovery.py +63 -0
- code2okf-0.1.0/web2md/tests/test_fetch.py +198 -0
- code2okf-0.1.0/web2md/tests/test_links.py +180 -0
- code2okf-0.1.0/web2md/tests/test_run.py +147 -0
- code2okf-0.1.0/web2md/tests/test_slugs.py +70 -0
- code2okf-0.1.0/web2md/tests/test_validate.py +153 -0
- code2okf-0.1.0/web2md/uv.lock +292 -0
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json
|
|
2
|
+
#
|
|
3
|
+
# CodeRabbit configuration for code2okf.
|
|
4
|
+
# Anything not listed here uses CodeRabbit's own default.
|
|
5
|
+
language: en-US
|
|
6
|
+
tone_instructions: "Be concise and focus on critical issues only. Do not comment on trivial matters, nitpicks, or stylistic preferences. Only flag issues that could cause bugs, security vulnerabilities, or significant maintainability problems."
|
|
7
|
+
early_access: false
|
|
8
|
+
enable_free_tier: true
|
|
9
|
+
reviews:
|
|
10
|
+
profile: quiet
|
|
11
|
+
request_changes_workflow: false
|
|
12
|
+
high_level_summary: true
|
|
13
|
+
high_level_summary_in_walkthrough: false
|
|
14
|
+
review_status: true
|
|
15
|
+
commit_status: true
|
|
16
|
+
fail_commit_status: false
|
|
17
|
+
collapse_walkthrough: true
|
|
18
|
+
changed_files_summary: true
|
|
19
|
+
sequence_diagrams: false
|
|
20
|
+
estimate_code_review_effort: true
|
|
21
|
+
assess_linked_issues: true
|
|
22
|
+
related_issues: true
|
|
23
|
+
related_prs: true
|
|
24
|
+
suggested_labels: true
|
|
25
|
+
auto_apply_labels: false
|
|
26
|
+
suggested_reviewers: true
|
|
27
|
+
auto_assign_reviewers: false
|
|
28
|
+
in_progress_fortune: false
|
|
29
|
+
poem: false
|
|
30
|
+
abort_on_close: true
|
|
31
|
+
# Generated, gitignored, or manually maintained content that is not reviewed:
|
|
32
|
+
# the wiki's input and output, the lockfile, the optional PDF step, and
|
|
33
|
+
# SPEC.md, which is the upstream OKF revision this repo builds against
|
|
34
|
+
# rather than code of ours to review.
|
|
35
|
+
path_filters:
|
|
36
|
+
- "!SPEC.md"
|
|
37
|
+
- "!uv.lock"
|
|
38
|
+
- "!md/**"
|
|
39
|
+
- "!okf/**/*.md"
|
|
40
|
+
- "!pdf2md/**"
|
|
41
|
+
- "!.cursor/mcp.json"
|
|
42
|
+
- "!.cursor/plans/**"
|
|
43
|
+
- "!.claude/plans/**"
|
|
44
|
+
path_instructions:
|
|
45
|
+
- path: "**/*.sh"
|
|
46
|
+
instructions: |
|
|
47
|
+
Apply robust Bash practices: strict error handling, quoted expansions,
|
|
48
|
+
arrays over constructed command strings, and no silently masked
|
|
49
|
+
failures. Resolve paths independently of the caller's working
|
|
50
|
+
directory, validate prerequisites early and exit non-zero with a clear
|
|
51
|
+
message on stderr, clean up temporary resources with traps, keep
|
|
52
|
+
secrets out of arguments and logs, and require ShellCheck-clean code.
|
|
53
|
+
- path: "**/spec.yaml"
|
|
54
|
+
instructions: |
|
|
55
|
+
For Docker Sandbox Kit specs, treat schema conformance as load-bearing:
|
|
56
|
+
flag renamed or restructured keys that a schema check would reject, and
|
|
57
|
+
say so rather than asserting the spec is valid. Keep capabilities
|
|
58
|
+
least-privilege and network access default-deny with a stated reason
|
|
59
|
+
for every allowed host, keep credentials proxy-managed and real secrets
|
|
60
|
+
out of the file, pin installed versions, make setup commands
|
|
61
|
+
idempotent, and bound retries and timeouts.
|
|
62
|
+
- path: ".github/workflows/**"
|
|
63
|
+
instructions: |
|
|
64
|
+
Apply GitHub Actions best practices: pin third-party actions and
|
|
65
|
+
downloaded binaries to a version, keep workflow permissions
|
|
66
|
+
least-privilege, avoid running untrusted input with elevated
|
|
67
|
+
privileges, fail loudly on download and script errors, and never echo
|
|
68
|
+
secrets into logs. Keep duplicated trigger configuration in sync.
|
|
69
|
+
- path: "**/*.md"
|
|
70
|
+
instructions: |
|
|
71
|
+
Review documentation against the rest of the diff rather than for prose
|
|
72
|
+
style: flag commands, paths, options, and examples that this change has
|
|
73
|
+
made wrong or stale, and instructions that contradict each other. Do
|
|
74
|
+
not raise wording, grammar, or line-length nitpicks.
|
|
75
|
+
- path: "**/*.py"
|
|
76
|
+
instructions: |
|
|
77
|
+
Review Python code for:
|
|
78
|
+
- PEP 8, type hints, docstrings, error handling, and performance. Flag mutable default arguments.
|
|
79
|
+
- Blocking calls inside async functions (use asyncio equivalents)
|
|
80
|
+
- API keys or secrets accidentally logged or exposed in error messages
|
|
81
|
+
- Missing context managers for network/file resources
|
|
82
|
+
- Unbounded retries or missing timeouts on external calls
|
|
83
|
+
- User-controlled strings passed unsanitized to shell commands or LLM prompts
|
|
84
|
+
- path: "**/tests/**/*.py"
|
|
85
|
+
instructions: |
|
|
86
|
+
Review test code for:
|
|
87
|
+
- Check pytest best practices, fixture usage, test isolation, and edge case coverage.
|
|
88
|
+
- Async test functions must have @pytest.mark.asyncio decorator
|
|
89
|
+
- Tests creating files/directories must have cleanup fixtures
|
|
90
|
+
- Prefer tmp_path over manual temp directories, and monkeypatch over
|
|
91
|
+
direct mutation of module state, so tests stay isolated.
|
|
92
|
+
- Tests must not perform real network I/O; HTTP belongs behind
|
|
93
|
+
httpx.MockTransport.
|
|
94
|
+
auto_review:
|
|
95
|
+
enabled: true
|
|
96
|
+
auto_incremental_review: true
|
|
97
|
+
ignore_title_keywords:
|
|
98
|
+
- "DO NOT REVIEW"
|
|
99
|
+
- "WIP"
|
|
100
|
+
drafts: false
|
|
101
|
+
# The web2md scraper (web2md/src/) and its pytest suite (web2md/tests/) are the
|
|
102
|
+
# only first-party code here.
|
|
103
|
+
finishing_touches:
|
|
104
|
+
docstrings:
|
|
105
|
+
enabled: true
|
|
106
|
+
unit_tests:
|
|
107
|
+
enabled: true
|
|
108
|
+
pre_merge_checks:
|
|
109
|
+
docstrings:
|
|
110
|
+
mode: "off"
|
|
111
|
+
title:
|
|
112
|
+
mode: warning
|
|
113
|
+
requirements: "Start with an imperative verb, name the area touched, and keep it under 72 characters."
|
|
114
|
+
description:
|
|
115
|
+
mode: warning
|
|
116
|
+
issue_assessment:
|
|
117
|
+
mode: warning
|
|
118
|
+
# Only deliberate overrides are listed. Every other tool is left at its
|
|
119
|
+
# default so it starts working on its own if this repo grows that language.
|
|
120
|
+
tools:
|
|
121
|
+
shellcheck:
|
|
122
|
+
enabled: true
|
|
123
|
+
checkmake:
|
|
124
|
+
enabled: true
|
|
125
|
+
yamllint:
|
|
126
|
+
enabled: true
|
|
127
|
+
actionlint:
|
|
128
|
+
enabled: true
|
|
129
|
+
markdownlint:
|
|
130
|
+
enabled: true
|
|
131
|
+
gitleaks:
|
|
132
|
+
enabled: true
|
|
133
|
+
checkov:
|
|
134
|
+
enabled: true
|
|
135
|
+
semgrep:
|
|
136
|
+
enabled: true
|
|
137
|
+
osvScanner:
|
|
138
|
+
enabled: true
|
|
139
|
+
# Grammar and style findings are exactly what tone_instructions above tells
|
|
140
|
+
# the reviewer not to raise, so leave this off rather than filtering it.
|
|
141
|
+
languagetool:
|
|
142
|
+
enabled: false
|
|
143
|
+
github-checks:
|
|
144
|
+
enabled: true
|
|
145
|
+
timeout_ms: 900000
|
|
146
|
+
ruff:
|
|
147
|
+
enabled: true
|
|
148
|
+
config_file: "web2md/pyproject.toml"
|
|
149
|
+
chat:
|
|
150
|
+
art: false
|
|
151
|
+
auto_reply: true
|
|
152
|
+
knowledge_base:
|
|
153
|
+
opt_out: false
|
|
154
|
+
web_search:
|
|
155
|
+
enabled: true
|
|
156
|
+
code_guidelines:
|
|
157
|
+
enabled: true
|
|
158
|
+
learnings:
|
|
159
|
+
scope: auto
|
|
160
|
+
issues:
|
|
161
|
+
scope: auto
|
|
162
|
+
pull_requests:
|
|
163
|
+
scope: auto
|
|
164
|
+
issue_enrichment:
|
|
165
|
+
auto_enrich:
|
|
166
|
+
enabled: true
|
|
167
|
+
planning:
|
|
168
|
+
enabled: true
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "0.2",
|
|
3
|
+
"language": "en,en-GB",
|
|
4
|
+
"ignorePaths": [
|
|
5
|
+
"md/**",
|
|
6
|
+
".claude/**",
|
|
7
|
+
".cursor/**",
|
|
8
|
+
"SPEC.md",
|
|
9
|
+
"CLAUDE.md",
|
|
10
|
+
"uv.lock",
|
|
11
|
+
"web2md/tests/**",
|
|
12
|
+
"scripts/inspectmd/tests/**",
|
|
13
|
+
"scripts/inspectokf/tests/**",
|
|
14
|
+
"scripts/sizeokf/tests/**",
|
|
15
|
+
"scripts/merkleokf/tests/**",
|
|
16
|
+
"tests/**"
|
|
17
|
+
],
|
|
18
|
+
"words": [
|
|
19
|
+
"okf",
|
|
20
|
+
"frontmatter",
|
|
21
|
+
"deepseek",
|
|
22
|
+
"litellm",
|
|
23
|
+
"gemini",
|
|
24
|
+
"thisismydesign",
|
|
25
|
+
"MarkerMarkdown",
|
|
26
|
+
"OpenRouter",
|
|
27
|
+
"Ollama",
|
|
28
|
+
"sbx",
|
|
29
|
+
"sbxenv",
|
|
30
|
+
"npmjs",
|
|
31
|
+
"maxsockets",
|
|
32
|
+
"earendil",
|
|
33
|
+
"passwordless",
|
|
34
|
+
"sandboxed",
|
|
35
|
+
"shellcheck",
|
|
36
|
+
"nullglob",
|
|
37
|
+
"nolog",
|
|
38
|
+
"pytest",
|
|
39
|
+
"pyproject",
|
|
40
|
+
"pipefail",
|
|
41
|
+
"psutil",
|
|
42
|
+
"fdfind",
|
|
43
|
+
"venv",
|
|
44
|
+
"pycache",
|
|
45
|
+
"httpx",
|
|
46
|
+
"pythonpath",
|
|
47
|
+
"testpaths",
|
|
48
|
+
"minversion",
|
|
49
|
+
"addopts",
|
|
50
|
+
"coderabbit",
|
|
51
|
+
"pycodestyle",
|
|
52
|
+
"pyflakes",
|
|
53
|
+
"pydocstyle",
|
|
54
|
+
"docstring",
|
|
55
|
+
"docstrings",
|
|
56
|
+
"conftest",
|
|
57
|
+
"monkeypatch",
|
|
58
|
+
"argparse",
|
|
59
|
+
"workbench",
|
|
60
|
+
"qwen",
|
|
61
|
+
"resumability",
|
|
62
|
+
"resumable",
|
|
63
|
+
"deepinfra",
|
|
64
|
+
"xhigh",
|
|
65
|
+
"gemma",
|
|
66
|
+
"idempotently",
|
|
67
|
+
"misordered",
|
|
68
|
+
"scannable",
|
|
69
|
+
"writable",
|
|
70
|
+
"inspectmd",
|
|
71
|
+
"uvx",
|
|
72
|
+
"hatchling",
|
|
73
|
+
"sdist",
|
|
74
|
+
"pypi",
|
|
75
|
+
"stdlib",
|
|
76
|
+
"context7",
|
|
77
|
+
"upstash",
|
|
78
|
+
"inspectokf",
|
|
79
|
+
"sizeokf",
|
|
80
|
+
"merkleokf",
|
|
81
|
+
"Merkle",
|
|
82
|
+
"worldbuilding",
|
|
83
|
+
"retcon",
|
|
84
|
+
"retconned",
|
|
85
|
+
"retcons",
|
|
86
|
+
"uncited",
|
|
87
|
+
"wikilinks",
|
|
88
|
+
"outlinks",
|
|
89
|
+
"dataview",
|
|
90
|
+
"throughline",
|
|
91
|
+
"plannable",
|
|
92
|
+
"leyline",
|
|
93
|
+
"Dragonsteel",
|
|
94
|
+
"Holocron",
|
|
95
|
+
"Dramatica",
|
|
96
|
+
"Egri",
|
|
97
|
+
"usermod",
|
|
98
|
+
"newgrp",
|
|
99
|
+
"okfctl",
|
|
100
|
+
"okflintrc",
|
|
101
|
+
"cwest"
|
|
102
|
+
]
|
|
103
|
+
}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: CI
|
|
3
|
+
|
|
4
|
+
on:
|
|
5
|
+
push:
|
|
6
|
+
branches: [main]
|
|
7
|
+
pull_request:
|
|
8
|
+
|
|
9
|
+
# The jobs only read the checked-out tree.
|
|
10
|
+
permissions:
|
|
11
|
+
contents: read
|
|
12
|
+
|
|
13
|
+
# Cancel superseded runs
|
|
14
|
+
concurrency:
|
|
15
|
+
group: ci-${{ github.workflow }}-${{ github.ref }}
|
|
16
|
+
cancel-in-progress: true
|
|
17
|
+
|
|
18
|
+
jobs:
|
|
19
|
+
# Host-side shell tests for state mount selection and relocation. The Linux
|
|
20
|
+
# runner must exercise the real bind-mount and idempotency cases.
|
|
21
|
+
test-shell:
|
|
22
|
+
runs-on: ubuntu-latest
|
|
23
|
+
timeout-minutes: 5
|
|
24
|
+
steps:
|
|
25
|
+
- name: Checkout
|
|
26
|
+
uses: actions/checkout@v4
|
|
27
|
+
with:
|
|
28
|
+
persist-credentials: false
|
|
29
|
+
|
|
30
|
+
- name: Test state mounts
|
|
31
|
+
run: make test-shell CODE2OKF_REQUIRE_BIND=1
|
|
32
|
+
|
|
33
|
+
# Lint Markdown, JSON, YAML, shell, spelling, and Python. Reuses `make lint`
|
|
34
|
+
# so the lint definition lives in one place (the Makefile). markdownlint runs
|
|
35
|
+
# via npx; yamllint and ruff run ephemerally at a pinned version via
|
|
36
|
+
# `uv tool run`, belonging to no project, so this job installs neither
|
|
37
|
+
# project's dependencies. cspell runs via npx. shellcheck and jq are both
|
|
38
|
+
# pre-installed on ubuntu-latest. The JSON check is syntax only (`jq empty`)
|
|
39
|
+
# — no schema validation.
|
|
40
|
+
lint:
|
|
41
|
+
runs-on: ubuntu-latest
|
|
42
|
+
timeout-minutes: 10
|
|
43
|
+
steps:
|
|
44
|
+
- name: Checkout
|
|
45
|
+
uses: actions/checkout@v4
|
|
46
|
+
with:
|
|
47
|
+
# No git operations after checkout, so don't leave the job token in
|
|
48
|
+
# .git/config where a later third-party step could read it.
|
|
49
|
+
persist-credentials: false
|
|
50
|
+
|
|
51
|
+
- name: Install uv
|
|
52
|
+
uses: astral-sh/setup-uv@v9.0.0
|
|
53
|
+
with:
|
|
54
|
+
enable-cache: true
|
|
55
|
+
|
|
56
|
+
- name: Lint (markdownlint, jq, yamllint, shellcheck, cspell, ruff)
|
|
57
|
+
run: make lint MARKDOWNLINT='npx --yes markdownlint-cli2'
|
|
58
|
+
|
|
59
|
+
# Unit-test the web2md scraper. Reuses `make test-web2md` so the definition
|
|
60
|
+
# stays in the Makefile. web2md is its own project, so its lockfile holds
|
|
61
|
+
# only the scraper's own deps plus pytest — marker-pdf / torch cannot reach
|
|
62
|
+
# it and there is nothing to exclude. The suite is offline
|
|
63
|
+
# (httpx.MockTransport), so this job needs no network beyond the install.
|
|
64
|
+
test-web2md:
|
|
65
|
+
runs-on: ubuntu-latest
|
|
66
|
+
timeout-minutes: 10
|
|
67
|
+
steps:
|
|
68
|
+
- name: Checkout
|
|
69
|
+
uses: actions/checkout@v4
|
|
70
|
+
with:
|
|
71
|
+
# No git operations after checkout, so don't leave the job token in
|
|
72
|
+
# .git/config where a later third-party step could read it.
|
|
73
|
+
persist-credentials: false
|
|
74
|
+
|
|
75
|
+
- name: Install uv
|
|
76
|
+
uses: astral-sh/setup-uv@v9.0.0
|
|
77
|
+
with:
|
|
78
|
+
enable-cache: true
|
|
79
|
+
|
|
80
|
+
- name: Test (pytest)
|
|
81
|
+
run: make test-web2md
|
|
82
|
+
|
|
83
|
+
# Unit-test the four host CLIs (inspectmd, inspectokf, sizeokf, merkleokf).
|
|
84
|
+
# Reuses `make test-clis`. Each CLI is its own project and lockfile;
|
|
85
|
+
# stdlib-only subjects under test (inspectokf mocks tree). Offline: no
|
|
86
|
+
# network beyond the install.
|
|
87
|
+
test-clis:
|
|
88
|
+
runs-on: ubuntu-latest
|
|
89
|
+
timeout-minutes: 10
|
|
90
|
+
steps:
|
|
91
|
+
- name: Checkout
|
|
92
|
+
uses: actions/checkout@v4
|
|
93
|
+
with:
|
|
94
|
+
# No git operations after checkout, so don't leave the job token in
|
|
95
|
+
# .git/config where a later third-party step could read it.
|
|
96
|
+
persist-credentials: false
|
|
97
|
+
|
|
98
|
+
- name: Install uv
|
|
99
|
+
uses: astral-sh/setup-uv@v9.0.0
|
|
100
|
+
with:
|
|
101
|
+
enable-cache: true
|
|
102
|
+
|
|
103
|
+
- name: Test (pytest)
|
|
104
|
+
run: make test-clis
|
|
105
|
+
|
|
106
|
+
# Unit-test the code2okf driver itself. Reuses `make test-code2okf`. Offline:
|
|
107
|
+
# every sbx call goes through the one seam in code2okf.sandbox, which the
|
|
108
|
+
# suite replaces with a fake rather than shelling out to a real sandbox.
|
|
109
|
+
test-code2okf:
|
|
110
|
+
runs-on: ubuntu-latest
|
|
111
|
+
timeout-minutes: 10
|
|
112
|
+
steps:
|
|
113
|
+
- name: Checkout
|
|
114
|
+
uses: actions/checkout@v4
|
|
115
|
+
with:
|
|
116
|
+
# No git operations after checkout, so don't leave the job token in
|
|
117
|
+
# .git/config where a later third-party step could read it.
|
|
118
|
+
persist-credentials: false
|
|
119
|
+
|
|
120
|
+
- name: Install uv
|
|
121
|
+
uses: astral-sh/setup-uv@v9.0.0
|
|
122
|
+
with:
|
|
123
|
+
enable-cache: true
|
|
124
|
+
|
|
125
|
+
- name: Test (pytest)
|
|
126
|
+
run: make test-code2okf
|
|
127
|
+
|
|
128
|
+
# Build the distribution and prove it works away from the checkout. Reuses
|
|
129
|
+
# `make dist` so the definition stays in the Makefile. `uv build` builds the
|
|
130
|
+
# wheel from the sdist, so an sdist missing kits/, SPEC.md or
|
|
131
|
+
# scripts/<cli>/ breaks here rather than after a release; the smoke run then
|
|
132
|
+
# exercises the *bundled* assets, which nothing run from the repository can
|
|
133
|
+
# do -- resources.py finds the real tree and every lookup succeeds either
|
|
134
|
+
# way. Offline apart from the installs: --dry-run creates no sandbox.
|
|
135
|
+
build-package:
|
|
136
|
+
runs-on: ubuntu-latest
|
|
137
|
+
timeout-minutes: 10
|
|
138
|
+
steps:
|
|
139
|
+
- name: Checkout
|
|
140
|
+
uses: actions/checkout@v4
|
|
141
|
+
with:
|
|
142
|
+
# No git operations after checkout, so don't leave the job token in
|
|
143
|
+
# .git/config where a later third-party step could read it.
|
|
144
|
+
persist-credentials: false
|
|
145
|
+
|
|
146
|
+
- name: Install uv
|
|
147
|
+
uses: astral-sh/setup-uv@v9.0.0
|
|
148
|
+
with:
|
|
149
|
+
enable-cache: true
|
|
150
|
+
|
|
151
|
+
- name: Build and smoke-test the distribution
|
|
152
|
+
run: make dist
|
|
153
|
+
|
|
154
|
+
# Validate kits/code2okf/spec.yaml against the current Sandbox Kit schema.
|
|
155
|
+
# Static check — no Docker or login; only the CLI download needs the network.
|
|
156
|
+
validate-kit:
|
|
157
|
+
runs-on: ubuntu-latest
|
|
158
|
+
timeout-minutes: 10
|
|
159
|
+
steps:
|
|
160
|
+
- name: Checkout
|
|
161
|
+
uses: actions/checkout@v4
|
|
162
|
+
with:
|
|
163
|
+
# No git operations after checkout, so don't leave the job token in
|
|
164
|
+
# .git/config where a later third-party step could read it.
|
|
165
|
+
persist-credentials: false
|
|
166
|
+
|
|
167
|
+
# Install the latest sbx CLI. "latest" is intentional: the schema is
|
|
168
|
+
# bundled in the binary, so this surfaces schema drift as soon as it ships.
|
|
169
|
+
# Install steps mirror docker/sbx-kits-contrib .github/workflows/tck.yml.
|
|
170
|
+
- name: Install sbx CLI
|
|
171
|
+
run: |
|
|
172
|
+
set -euo pipefail
|
|
173
|
+
curl -fsSL \
|
|
174
|
+
"https://github.com/docker/sbx-releases/releases/latest/download/DockerSandboxes-linux.tar.gz" \
|
|
175
|
+
-o /tmp/DockerSandboxes-linux.tar.gz
|
|
176
|
+
tar xzf /tmp/DockerSandboxes-linux.tar.gz -C /tmp
|
|
177
|
+
sudo PREFIX="${HOME}/.docker/sbx" /tmp/docker-sbx/install.sh
|
|
178
|
+
echo "${HOME}/.docker/sbx/bin" >> "$GITHUB_PATH"
|
|
179
|
+
|
|
180
|
+
- name: Verify sbx
|
|
181
|
+
run: sbx version
|
|
182
|
+
|
|
183
|
+
- name: Validate Pi kit spec
|
|
184
|
+
run: make validate
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Release
|
|
3
|
+
|
|
4
|
+
# A tag push is the release: pushing vX.Y.Z verifies the repository agrees with
|
|
5
|
+
# itself, builds the distribution once, publishes it to PyPI, and then creates a
|
|
6
|
+
# GitHub Release whose notes are the matching section of CHANGELOG.md and whose
|
|
7
|
+
# assets are those same artifacts.
|
|
8
|
+
#
|
|
9
|
+
# The job order is deliberate and must stay a chain, not a fan-out. Two jobs
|
|
10
|
+
# that both merely `needs: [verify]` would run concurrently, and the one
|
|
11
|
+
# attaching assets could reach a Release that does not exist yet. Publishing
|
|
12
|
+
# first also means a tag on the Releases page always corresponds to a version
|
|
13
|
+
# that is actually installable.
|
|
14
|
+
#
|
|
15
|
+
# One build feeds both publishers, which is what makes a re-run safe: PyPI
|
|
16
|
+
# treats an upload of a byte-identical file as idempotent, so re-running after
|
|
17
|
+
# a partial failure re-uploads the same bytes rather than colliding with them.
|
|
18
|
+
#
|
|
19
|
+
# All the version and notes logic lives in scripts/, so `make lint`
|
|
20
|
+
# shellchecks the helpers and they can be rehearsed locally.
|
|
21
|
+
|
|
22
|
+
on:
|
|
23
|
+
push:
|
|
24
|
+
# Digit-only, so vX.Y.Z-rc1 and other shapes cannot trigger a release.
|
|
25
|
+
# Matches the pattern scripts/check-release-tag.sh enforces.
|
|
26
|
+
tags: ["v[0-9]+.[0-9]+.[0-9]+"]
|
|
27
|
+
|
|
28
|
+
# Narrowed further per job: github-release writes to the repository,
|
|
29
|
+
# publish-pypi mints an OIDC token, and verify and build need neither.
|
|
30
|
+
permissions:
|
|
31
|
+
contents: read
|
|
32
|
+
|
|
33
|
+
# Never cancel a release in flight.
|
|
34
|
+
concurrency:
|
|
35
|
+
group: release-${{ github.ref }}
|
|
36
|
+
cancel-in-progress: false
|
|
37
|
+
|
|
38
|
+
jobs:
|
|
39
|
+
# Gate the release on the repo agreeing with itself before anything is
|
|
40
|
+
# announced. `make lint` is the substance here: it already fails when VERSION
|
|
41
|
+
# and CHANGELOG.md's latest release heading disagree, so a tag whose version
|
|
42
|
+
# is inconsistent cannot create a Release.
|
|
43
|
+
verify:
|
|
44
|
+
runs-on: ubuntu-latest
|
|
45
|
+
timeout-minutes: 10
|
|
46
|
+
outputs:
|
|
47
|
+
version: ${{ steps.version.outputs.version }}
|
|
48
|
+
steps:
|
|
49
|
+
- name: Checkout
|
|
50
|
+
uses: actions/checkout@v4
|
|
51
|
+
with:
|
|
52
|
+
# No git operations after checkout, so don't leave the job token in
|
|
53
|
+
# .git/config where a later third-party step could read it.
|
|
54
|
+
persist-credentials: false
|
|
55
|
+
|
|
56
|
+
# The tag is authoritative and must agree with VERSION. check-release-tag.sh
|
|
57
|
+
# writes version= on fd 3, which is why it is redirected rather than
|
|
58
|
+
# piped: its human output must not reach $GITHUB_OUTPUT.
|
|
59
|
+
- name: Resolve version
|
|
60
|
+
id: version
|
|
61
|
+
run: ./scripts/check-release-tag.sh "${GITHUB_REF_NAME}" 3>>"$GITHUB_OUTPUT"
|
|
62
|
+
|
|
63
|
+
# Fail an empty changelog section here, before a Release is created.
|
|
64
|
+
# `make lint` cannot catch this: it checks only that the latest
|
|
65
|
+
# `## [X.Y.Z]` heading exists and agrees with VERSION, and a heading with
|
|
66
|
+
# no body passes that. The github-release job runs the same script again
|
|
67
|
+
# for the notes themselves, so there is one definition of "non-empty".
|
|
68
|
+
- name: Check the release notes are not empty
|
|
69
|
+
env:
|
|
70
|
+
RELEASE_VERSION: ${{ steps.version.outputs.version }}
|
|
71
|
+
run: ./scripts/release-notes.sh "${RELEASE_VERSION}" >/dev/null
|
|
72
|
+
|
|
73
|
+
- name: Install uv
|
|
74
|
+
uses: astral-sh/setup-uv@v9.0.0
|
|
75
|
+
with:
|
|
76
|
+
enable-cache: true
|
|
77
|
+
|
|
78
|
+
- name: Lint (includes the version-agreement check)
|
|
79
|
+
run: make lint MARKDOWNLINT='npx --yes markdownlint-cli2'
|
|
80
|
+
|
|
81
|
+
# Build the wheel and the sdist once, and hand the same bytes to both
|
|
82
|
+
# publishers below. `make dist` is the same target CI runs on every pull
|
|
83
|
+
# request: it builds both artifacts, rebuilds the wheel from the sdist in a
|
|
84
|
+
# scratch directory, and smoke-tests the result from outside the checkout, so
|
|
85
|
+
# a release cannot ship an sdist that cannot rebuild itself.
|
|
86
|
+
build:
|
|
87
|
+
needs: [verify]
|
|
88
|
+
runs-on: ubuntu-latest
|
|
89
|
+
timeout-minutes: 10
|
|
90
|
+
steps:
|
|
91
|
+
- name: Checkout
|
|
92
|
+
uses: actions/checkout@v4
|
|
93
|
+
with:
|
|
94
|
+
# No git operations after checkout, so don't leave the job token in
|
|
95
|
+
# .git/config where a later third-party step could read it.
|
|
96
|
+
persist-credentials: false
|
|
97
|
+
|
|
98
|
+
- name: Install uv
|
|
99
|
+
uses: astral-sh/setup-uv@v9.0.0
|
|
100
|
+
with:
|
|
101
|
+
enable-cache: true
|
|
102
|
+
|
|
103
|
+
- name: Build and smoke-test the distribution
|
|
104
|
+
run: make dist
|
|
105
|
+
|
|
106
|
+
# `overwrite` defaults to false, which fails the upload outright when an
|
|
107
|
+
# artifact of this name already exists in the run. Re-running the whole
|
|
108
|
+
# workflow after a partial failure would then die here, before reaching
|
|
109
|
+
# PyPI — so overwrite rather than collide, matching the re-run safety the
|
|
110
|
+
# rest of this workflow is built for.
|
|
111
|
+
- name: Upload the distribution
|
|
112
|
+
uses: actions/upload-artifact@v7
|
|
113
|
+
with:
|
|
114
|
+
name: dist
|
|
115
|
+
path: dist/
|
|
116
|
+
if-no-files-found: error
|
|
117
|
+
overwrite: true
|
|
118
|
+
|
|
119
|
+
# Publish to PyPI by trusted publishing: no token exists to leak or rotate,
|
|
120
|
+
# and the `pypi` environment is what PyPI's publisher configuration is keyed
|
|
121
|
+
# to. A separate job from the build on purpose — the OIDC credential is never
|
|
122
|
+
# present in the job that produced the artifacts.
|
|
123
|
+
publish-pypi:
|
|
124
|
+
needs: [build]
|
|
125
|
+
runs-on: ubuntu-latest
|
|
126
|
+
timeout-minutes: 10
|
|
127
|
+
environment:
|
|
128
|
+
name: pypi
|
|
129
|
+
url: https://pypi.org/p/code2okf
|
|
130
|
+
permissions:
|
|
131
|
+
# Mint the OIDC token PyPI exchanges for an upload token. Nothing else.
|
|
132
|
+
id-token: write
|
|
133
|
+
steps:
|
|
134
|
+
- name: Install uv
|
|
135
|
+
uses: astral-sh/setup-uv@v9.0.0
|
|
136
|
+
with:
|
|
137
|
+
enable-cache: false
|
|
138
|
+
|
|
139
|
+
- name: Download the distribution
|
|
140
|
+
uses: actions/download-artifact@v8
|
|
141
|
+
with:
|
|
142
|
+
name: dist
|
|
143
|
+
path: dist/
|
|
144
|
+
|
|
145
|
+
# `always` rather than uv's default `automatic`: with no credentials
|
|
146
|
+
# configured the default silently falls back and the upload fails later
|
|
147
|
+
# as an opaque 403, while `always` fails here, saying the OIDC exchange
|
|
148
|
+
# is what went wrong.
|
|
149
|
+
# The artifacts are named rather than left to uv's default `dist/*`:
|
|
150
|
+
# `uv build` also drops a .gitignore in there, and naming the two files
|
|
151
|
+
# keeps anything else that appears out of the upload.
|
|
152
|
+
- name: Publish to PyPI
|
|
153
|
+
run: uv publish --trusted-publishing always dist/*.tar.gz dist/*.whl
|
|
154
|
+
|
|
155
|
+
# Create the GitHub Release. A tag and a Release are different objects and
|
|
156
|
+
# pushing a tag never creates one, so without this the Releases page stays
|
|
157
|
+
# empty however many versions ship. The notes are the changelog's own section,
|
|
158
|
+
# so there is no second description of a release to drift.
|
|
159
|
+
github-release:
|
|
160
|
+
# verify for the version output, publish-pypi for the ordering: the assets
|
|
161
|
+
# attached here are the ones already on PyPI.
|
|
162
|
+
needs: [verify, publish-pypi]
|
|
163
|
+
runs-on: ubuntu-latest
|
|
164
|
+
timeout-minutes: 10
|
|
165
|
+
permissions:
|
|
166
|
+
# The only job in this workflow that writes to the repository.
|
|
167
|
+
contents: write
|
|
168
|
+
steps:
|
|
169
|
+
- name: Checkout
|
|
170
|
+
uses: actions/checkout@v4
|
|
171
|
+
with:
|
|
172
|
+
# Needed for CHANGELOG.md and the script. gh authenticates with
|
|
173
|
+
# GH_TOKEN below, not with the checkout credential.
|
|
174
|
+
persist-credentials: false
|
|
175
|
+
|
|
176
|
+
- name: Download the distribution
|
|
177
|
+
uses: actions/download-artifact@v8
|
|
178
|
+
with:
|
|
179
|
+
name: dist
|
|
180
|
+
path: dist/
|
|
181
|
+
|
|
182
|
+
- name: Create the GitHub Release
|
|
183
|
+
env:
|
|
184
|
+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
185
|
+
TAG: ${{ github.ref_name }}
|
|
186
|
+
RELEASE_VERSION: ${{ needs.verify.outputs.version }}
|
|
187
|
+
run: |
|
|
188
|
+
set -euo pipefail
|
|
189
|
+
# Re-running a release is normal, so converge rather than fail: an
|
|
190
|
+
# existing Release keeps its notes -- they may have been edited by
|
|
191
|
+
# hand -- and only its assets are refreshed, which is what a re-run
|
|
192
|
+
# after a half-finished upload needs.
|
|
193
|
+
if gh release view "${TAG}" >/dev/null 2>&1; then
|
|
194
|
+
echo "NOTICE: release ${TAG} already exists — refreshing its assets only"
|
|
195
|
+
gh release upload "${TAG}" dist/* --clobber
|
|
196
|
+
exit 0
|
|
197
|
+
fi
|
|
198
|
+
# Read the notes first and only then create, rather than piping one
|
|
199
|
+
# into the other. In a pipeline both sides start together, so a
|
|
200
|
+
# failing extractor would hand gh an empty stdin and the Release
|
|
201
|
+
# would be created empty before pipefail reported the failure — and
|
|
202
|
+
# the existing-release check above would then skip it forever. The
|
|
203
|
+
# verify job makes that unreachable in practice; this makes it
|
|
204
|
+
# impossible.
|
|
205
|
+
notes="$(./scripts/release-notes.sh "${RELEASE_VERSION}")"
|
|
206
|
+
# --verify-tag refuses to invent a tag that does not exist, turning a
|
|
207
|
+
# typo into a failure instead of a stray tag.
|
|
208
|
+
printf '%s\n' "${notes}" |
|
|
209
|
+
gh release create "${TAG}" --title "${TAG}" --verify-tag --notes-file - dist/*
|