toolframe-core 0.6.2__tar.gz → 0.6.4__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.
Files changed (161) hide show
  1. toolframe_core-0.6.4/.dockerignore +15 -0
  2. toolframe_core-0.6.4/.github/actions/scan-container/action.yml +44 -0
  3. toolframe_core-0.6.4/.github/dependabot.yml +50 -0
  4. toolframe_core-0.6.4/.github/workflows/ci.yml +52 -0
  5. toolframe_core-0.6.4/.github/workflows/container-security.yml +52 -0
  6. toolframe_core-0.6.4/.github/workflows/container.yml +221 -0
  7. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/.github/workflows/launcher.yml +3 -0
  8. toolframe_core-0.6.4/.github/workflows/pr-policy.yml +31 -0
  9. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/.github/workflows/publish.yml +68 -28
  10. toolframe_core-0.6.4/.github/workflows/quality.yml +49 -0
  11. toolframe_core-0.6.4/.github/workflows/validate.yml +214 -0
  12. toolframe_core-0.6.4/.pre-commit-config.yaml +29 -0
  13. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/CHANGELOG.md +17 -0
  14. toolframe_core-0.6.4/CONTRIBUTING.md +47 -0
  15. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/Cargo.lock +1 -1
  16. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/Cargo.toml +1 -1
  17. toolframe_core-0.6.4/Dockerfile +107 -0
  18. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/PKG-INFO +11 -1
  19. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/README.md +10 -0
  20. toolframe_core-0.6.4/cchk.toml +10 -0
  21. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/docs/architecture.md +3 -0
  22. toolframe_core-0.6.4/docs/artifacts.md +73 -0
  23. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/docs/ci.md +59 -8
  24. toolframe_core-0.6.4/docs/container.md +247 -0
  25. toolframe_core-0.6.4/docs/intel-companion.md +100 -0
  26. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/docs/postgresql-state.md +1 -1
  27. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/docs/releasing.md +33 -13
  28. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/pyproject.toml +1 -1
  29. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/scripts/build-launcher.py +10 -11
  30. toolframe_core-0.6.4/scripts/check-container-security.py +128 -0
  31. toolframe_core-0.6.4/scripts/check_branch_name.py +59 -0
  32. toolframe_core-0.6.4/scripts/ci/artifacts.py +496 -0
  33. toolframe_core-0.6.4/scripts/ci/intel-companion.json +29 -0
  34. toolframe_core-0.6.4/scripts/ci/intel_companion.py +365 -0
  35. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/scripts/ci/prepare-launcher.py +2 -1
  36. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/scripts/ci/validate.py +2 -1
  37. toolframe_core-0.6.4/scripts/container-healthcheck.py +23 -0
  38. toolframe_core-0.6.4/scripts/harden-container.py +41 -0
  39. toolframe_core-0.6.4/scripts/prepare-container.py +88 -0
  40. toolframe_core-0.6.4/scripts/verify-container.py +335 -0
  41. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/src/main.rs +8 -8
  42. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/src/toolframe_core/__init__.py +1 -1
  43. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/src/toolframe_core/api.py +1 -0
  44. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/src/toolframe_core/host.py +3 -1
  45. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/tests/test_acceptance.py +40 -0
  46. toolframe_core-0.6.4/tests/test_ci_artifacts.py +563 -0
  47. toolframe_core-0.6.4/tests/test_container_release.py +98 -0
  48. toolframe_core-0.6.4/tests/test_container_security.py +105 -0
  49. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/tests/test_core_state.py +1 -0
  50. toolframe_core-0.6.4/tests/test_intel_companion.py +314 -0
  51. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/tests/test_mcp_auth.py +4 -3
  52. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/uv.lock +1 -1
  53. toolframe_core-0.6.2/.github/workflows/ci.yml +0 -20
  54. toolframe_core-0.6.2/.github/workflows/validate.yml +0 -102
  55. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/.gitignore +0 -0
  56. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/LICENSE +0 -0
  57. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/NOTICE +0 -0
  58. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/companion-wheels.txt +0 -0
  59. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/docs/adr/0001-explicit-dashboard-access-mode.md +0 -0
  60. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/docs/adr/0002-scoped-passwords-and-public-business-entrances.md +0 -0
  61. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/docs/adr/0003-public-fallback-on-auth-error-or-disablement.md +0 -0
  62. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/docs/adr/0004-separate-auth-ownership-from-dashboard-presentation.md +0 -0
  63. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/docs/adr/0005-password-only-login-and-secret-reuse.md +0 -0
  64. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/docs/adr/0006-require-explicit-plugin-authorization-contracts.md +0 -0
  65. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/docs/adr/0007-independent-mcp-bearer-authentication.md +0 -0
  66. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/docs/adr/0008-shared-oidc-authentication.md +0 -0
  67. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/docs/adr/0009-replaceable-core-journal.md +0 -0
  68. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/docs/adr/0010-multiple-sql-providers.md +0 -0
  69. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/docs/adr/0011-safe-new-application-access.md +0 -0
  70. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/docs/adr/0012-optional-runtime-tracing.md +0 -0
  71. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/docs/adr/0013-context-logging.md +0 -0
  72. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/docs/authentication.md +0 -0
  73. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/docs/dependency-graph.md +0 -0
  74. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/docs/glossary.md +0 -0
  75. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/docs/mcp-authentication.md +0 -0
  76. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/docs/object-storage.md +0 -0
  77. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/docs/offline-maintenance.md +0 -0
  78. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/docs/oidc-authentication.md +0 -0
  79. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/docs/runtime.md +0 -0
  80. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/docs/sql-storage.md +0 -0
  81. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/docs/testing.md +0 -0
  82. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/docs/tracing.md +0 -0
  83. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/packaging/launcher/NOTICE +0 -0
  84. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/packaging/launcher/README.md +0 -0
  85. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/packaging/launcher/pyproject.toml +0 -0
  86. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/scripts/build-release.sh +0 -0
  87. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/scripts/ci/check-launcher-wheel.py +0 -0
  88. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/scripts/ci/check-postgres.py +0 -0
  89. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/scripts/ci/check-release.py +0 -0
  90. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/scripts/ci/dependencies.json +0 -0
  91. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/scripts/dev-wheelhouse.sh +0 -0
  92. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/scripts/verify-auth-upgrade.py +0 -0
  93. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/scripts/verify-auth.py +0 -0
  94. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/scripts/verify-dependencies.py +0 -0
  95. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/scripts/verify-network.py +0 -0
  96. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/scripts/verify-operation-history.py +0 -0
  97. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/scripts/verify-release.py +0 -0
  98. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/scripts/verify-retained-plugins.py +0 -0
  99. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/scripts/verify-scaffold.py +0 -0
  100. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/scripts/verify-skill.py +0 -0
  101. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/src/companions.rs +0 -0
  102. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/src/toolframe_core/_state_postgres.py +0 -0
  103. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/src/toolframe_core/_state_sqlite.py +0 -0
  104. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/src/toolframe_core/access.py +0 -0
  105. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/src/toolframe_core/bundled_skills/toolframe-plugin-design/LICENSE +0 -0
  106. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/src/toolframe_core/bundled_skills/toolframe-plugin-design/SKILL.md +0 -0
  107. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/src/toolframe_core/bundled_skills/toolframe-plugin-design/agents/openai.yaml +0 -0
  108. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/src/toolframe_core/bundled_skills/toolframe-plugin-design/assets/sample-plugin/LICENSE +0 -0
  109. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/src/toolframe_core/bundled_skills/toolframe-plugin-design/assets/sample-plugin/pyproject.toml +0 -0
  110. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/src/toolframe_core/bundled_skills/toolframe-plugin-design/assets/sample-plugin/src/toolframe_sample_notes/__init__.py +0 -0
  111. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/src/toolframe_core/bundled_skills/toolframe-plugin-design/assets/sample-plugin/src/toolframe_sample_notes/docs/usage.md +0 -0
  112. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/src/toolframe_core/bundled_skills/toolframe-plugin-design/assets/sample-plugin/src/toolframe_sample_notes/migrations/0001_init.sql +0 -0
  113. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/src/toolframe_core/bundled_skills/toolframe-plugin-design/assets/sample-plugin/src/toolframe_sample_notes/page.py +0 -0
  114. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/src/toolframe_core/bundled_skills/toolframe-plugin-design/assets/sample-plugin/src/toolframe_sample_notes/plugin.py +0 -0
  115. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/src/toolframe_core/bundled_skills/toolframe-plugin-design/assets/sample-plugin/src/toolframe_sample_notes/service.py +0 -0
  116. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/src/toolframe_core/bundled_skills/toolframe-plugin-design/evals/cases.json +0 -0
  117. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/src/toolframe_core/bundled_skills/toolframe-plugin-design/references/design.md +0 -0
  118. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/src/toolframe_core/bundled_skills/toolframe-plugin-design/references/operations.md +0 -0
  119. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/src/toolframe_core/bundled_skills/toolframe-plugin-design/references/plugin-api.md +0 -0
  120. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/src/toolframe_core/cli.py +0 -0
  121. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/src/toolframe_core/config.py +0 -0
  122. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/src/toolframe_core/diagnostics.py +0 -0
  123. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/src/toolframe_core/graph.py +0 -0
  124. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/src/toolframe_core/maintenance.py +0 -0
  125. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/src/toolframe_core/mcp_access.py +0 -0
  126. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/src/toolframe_core/network.py +0 -0
  127. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/src/toolframe_core/oidc_access.py +0 -0
  128. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/src/toolframe_core/packages.py +0 -0
  129. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/src/toolframe_core/process.py +0 -0
  130. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/src/toolframe_core/redaction.py +0 -0
  131. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/src/toolframe_core/scaffold.py +0 -0
  132. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/src/toolframe_core/skills.py +0 -0
  133. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/src/toolframe_core/state.py +0 -0
  134. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/src/toolframe_core/state_admin.py +0 -0
  135. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/src/toolframe_core/stores.py +0 -0
  136. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/src/toolframe_core/templates.json +0 -0
  137. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/src/toolframe_core/templates.py +0 -0
  138. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/src/uv.rs +0 -0
  139. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/tests/test_access_policy.py +0 -0
  140. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/tests/test_architecture.py +0 -0
  141. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/tests/test_auth.py +0 -0
  142. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/tests/test_bundles.py +0 -0
  143. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/tests/test_cli.py +0 -0
  144. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/tests/test_diagnostics.py +0 -0
  145. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/tests/test_foundations.py +0 -0
  146. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/tests/test_host.py +0 -0
  147. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/tests/test_maintenance.py +0 -0
  148. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/tests/test_managed_tasks.py +0 -0
  149. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/tests/test_mixed_storage.py +0 -0
  150. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/tests/test_network.py +0 -0
  151. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/tests/test_object_store.py +0 -0
  152. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/tests/test_oidc.py +0 -0
  153. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/tests/test_operation_history.py +0 -0
  154. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/tests/test_process.py +0 -0
  155. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/tests/test_redaction.py +0 -0
  156. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/tests/test_retained_plugins.py +0 -0
  157. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/tests/test_scaffold.py +0 -0
  158. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/tests/test_skills.py +0 -0
  159. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/tests/test_storage_bindings.py +0 -0
  160. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/tests/test_tracing.py +0 -0
  161. {toolframe_core-0.6.2 → toolframe_core-0.6.4}/uv-release-manifest.txt +0 -0
@@ -0,0 +1,15 @@
1
+ **
2
+ !Dockerfile
3
+ !scripts/
4
+ !scripts/container-healthcheck.py
5
+ !scripts/harden-container.py
6
+ !build/
7
+ !build/container/
8
+ !build/container/amd64/
9
+ !build/container/amd64/toolframe
10
+ !build/container/amd64/LICENSE
11
+ !build/container/amd64/NOTICE
12
+ !build/container/arm64/
13
+ !build/container/arm64/toolframe
14
+ !build/container/arm64/LICENSE
15
+ !build/container/arm64/NOTICE
@@ -0,0 +1,44 @@
1
+ name: Scan a Toolframe container
2
+ description: Retain the full vulnerability inventory and enforce publication policy
3
+ inputs:
4
+ image:
5
+ description: Local image tag or public registry reference
6
+ required: true
7
+ platform:
8
+ description: Linux platform to scan
9
+ required: true
10
+ image-source:
11
+ description: Trivy image source (docker or remote)
12
+ required: true
13
+ runs:
14
+ using: composite
15
+ steps:
16
+ - uses: aquasecurity/setup-trivy@81e514348e19b6112ce2a7e3ecbafe19c1e1f567
17
+ with:
18
+ version: v0.76.0
19
+ cache: false
20
+ - name: Scan every severity and keep the package inventory
21
+ shell: bash
22
+ env:
23
+ SCAN_IMAGE: ${{ inputs.image }}
24
+ SCAN_PLATFORM: ${{ inputs.platform }}
25
+ SCAN_SOURCE: ${{ inputs.image-source }}
26
+ run: |
27
+ mkdir -p build/security
28
+ trivy image --image-src "$SCAN_SOURCE" --platform "$SCAN_PLATFORM" \
29
+ --scanners vuln --ignorefile '' --disable-telemetry --list-all-pkgs \
30
+ --timeout 10m --format json --output build/security/scan.json "$SCAN_IMAGE"
31
+ trivy version --format json > build/security/scanner.json
32
+ trivy convert --format cyclonedx --output build/security/sbom.cdx.json build/security/scan.json
33
+ - name: Enforce the security policy
34
+ shell: bash
35
+ run: |
36
+ python3 scripts/check-container-security.py build/security/scan.json \
37
+ --summary build/security/summary.md
38
+ - name: Add findings to the run summary
39
+ if: always()
40
+ shell: bash
41
+ run: |
42
+ if [ -f build/security/summary.md ]; then
43
+ cat build/security/summary.md >> "$GITHUB_STEP_SUMMARY"
44
+ fi
@@ -0,0 +1,50 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: docker
4
+ directory: /
5
+ schedule:
6
+ interval: weekly
7
+ day: monday
8
+ time: '04:23'
9
+ timezone: Etc/UTC
10
+ open-pull-requests-limit: 4
11
+ commit-message:
12
+ prefix: fix(container)
13
+ pull-request-branch-name:
14
+ prefix: chore
15
+ template: '{prefix}/{name}'
16
+ groups:
17
+ # Catch every version and security update, including major versions.
18
+ # To split a dependency out, add a named group before these catch-alls;
19
+ # exclusions would fall back to noncompliant solo dependency/version names.
20
+ container-dependencies:
21
+ applies-to: version-updates
22
+ patterns: ['*']
23
+ container-security:
24
+ applies-to: security-updates
25
+ patterns: ['*']
26
+ ignore:
27
+ # The 0.6.3 launcher accepts uv >=0.12.2,<0.13.0.
28
+ # Widen this only alongside a compatible launcher release.
29
+ - dependency-name: astral-sh/uv
30
+ versions: ['>=0.13.0']
31
+ - package-ecosystem: github-actions
32
+ directory: /
33
+ schedule:
34
+ interval: weekly
35
+ day: monday
36
+ time: '04:23'
37
+ timezone: Etc/UTC
38
+ open-pull-requests-limit: 4
39
+ commit-message:
40
+ prefix: chore(ci)
41
+ pull-request-branch-name:
42
+ prefix: chore
43
+ template: '{prefix}/{name}'
44
+ groups:
45
+ actions-dependencies:
46
+ applies-to: version-updates
47
+ patterns: ['*']
48
+ actions-security:
49
+ applies-to: security-updates
50
+ patterns: ['*']
@@ -0,0 +1,52 @@
1
+ name: CI
2
+
3
+ on:
4
+ pull_request:
5
+ push:
6
+ # Publication independently verifies/promotes the selected release tag.
7
+ branches: [main]
8
+ workflow_dispatch:
9
+ inputs:
10
+ rebuild:
11
+ description: Run all checks and builds even if validated artifacts exist
12
+ type: boolean
13
+ default: false
14
+
15
+ permissions:
16
+ contents: read
17
+ pull-requests: read
18
+ actions: read
19
+
20
+ concurrency:
21
+ group: ci-${{ github.workflow }}-${{ github.ref }}
22
+ cancel-in-progress: true
23
+
24
+ jobs:
25
+ quality:
26
+ uses: ./.github/workflows/quality.yml
27
+
28
+ validate:
29
+ needs: quality
30
+ uses: ./.github/workflows/validate.yml
31
+ with:
32
+ reuse-stage: ${{ github.ref == 'refs/heads/main' && 'main' || 'none' }}
33
+ rebuild: ${{ inputs.rebuild || false }}
34
+ secrets: inherit
35
+
36
+ result:
37
+ name: CI result
38
+ if: always()
39
+ needs: [quality, validate]
40
+ runs-on: ubuntu-24.04
41
+ timeout-minutes: 2
42
+ steps:
43
+ # Require this check when configuring branch protection. A skipped
44
+ # validation job must not turn a failed prerequisite into a green check.
45
+ - name: Require successful checks and validation
46
+ env:
47
+ QUALITY_RESULT: ${{ needs.quality.result }}
48
+ VALIDATE_RESULT: ${{ needs.validate.result }}
49
+ run: |
50
+ echo "Quality: $QUALITY_RESULT; validation: $VALIDATE_RESULT"
51
+ test "$QUALITY_RESULT" = success
52
+ test "$VALIDATE_RESULT" = success
@@ -0,0 +1,52 @@
1
+ name: Container security
2
+
3
+ on:
4
+ schedule:
5
+ - cron: '23 3 * * *'
6
+ workflow_dispatch:
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ concurrency:
12
+ group: container-security-${{ github.ref }}
13
+ cancel-in-progress: false
14
+
15
+ jobs:
16
+ scan:
17
+ name: ${{ matrix.variant }} (${{ matrix.arch }})
18
+ runs-on: ubuntu-24.04
19
+ timeout-minutes: 20
20
+ strategy:
21
+ fail-fast: false
22
+ matrix:
23
+ variant: [standard, distroless]
24
+ arch: [amd64, arm64]
25
+ include:
26
+ - variant: standard
27
+ tag: latest
28
+ - variant: distroless
29
+ tag: distroless
30
+ steps:
31
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
32
+ with:
33
+ persist-credentials: false
34
+ - name: Select the public image
35
+ id: image
36
+ env:
37
+ OWNER: ${{ github.repository_owner }}
38
+ TAG: ${{ matrix.tag }}
39
+ run: echo "ref=ghcr.io/${OWNER,,}/toolframe:$TAG" >> "$GITHUB_OUTPUT"
40
+ - uses: ./.github/actions/scan-container
41
+ with:
42
+ image: ${{ steps.image.outputs.ref }}
43
+ platform: linux/${{ matrix.arch }}
44
+ image-source: remote
45
+ - name: Save findings and the inventory
46
+ if: always()
47
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
48
+ with:
49
+ name: container-security-${{ matrix.variant }}-${{ matrix.arch }}
50
+ path: build/security/
51
+ if-no-files-found: warn
52
+ retention-days: 7
@@ -0,0 +1,221 @@
1
+ name: Container images
2
+
3
+ on:
4
+ pull_request:
5
+ paths:
6
+ - Dockerfile
7
+ - .dockerignore
8
+ - .github/workflows/container.yml
9
+ - .github/workflows/container-security.yml
10
+ - .github/actions/scan-container/**
11
+ - scripts/*container*.py
12
+ - tests/test_container_*.py
13
+ workflow_call:
14
+ inputs:
15
+ publish:
16
+ type: boolean
17
+ default: false
18
+ release_artifacts:
19
+ description: Use the validated launcher artifacts from this workflow run
20
+ type: boolean
21
+ default: false
22
+ workflow_dispatch:
23
+ inputs:
24
+ publish:
25
+ description: Publish both tested variants to GHCR
26
+ type: boolean
27
+ default: false
28
+
29
+ permissions:
30
+ contents: read
31
+
32
+ jobs:
33
+ build:
34
+ name: ${{ matrix.variant }} (${{ matrix.arch }})
35
+ runs-on: ${{ matrix.runner }}
36
+ timeout-minutes: 30
37
+ permissions:
38
+ contents: read
39
+ packages: write
40
+ strategy:
41
+ fail-fast: false
42
+ matrix:
43
+ variant: [standard, distroless]
44
+ arch: [amd64, arm64]
45
+ include:
46
+ - arch: amd64
47
+ runner: ubuntu-24.04
48
+ target: x86_64-unknown-linux-gnu
49
+ - arch: arm64
50
+ runner: ubuntu-24.04-arm
51
+ target: aarch64-unknown-linux-gnu
52
+ outputs:
53
+ version: ${{ steps.metadata.outputs.version }}
54
+ image: ${{ steps.metadata.outputs.image }}
55
+ steps:
56
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
57
+ with:
58
+ persist-credentials: false
59
+ - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
60
+ with:
61
+ python-version: '3.14.7'
62
+ - uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069
63
+ - name: Read the version and registry namespace
64
+ id: metadata
65
+ env:
66
+ REPOSITORY_OWNER: ${{ github.repository_owner }}
67
+ GH_TOKEN: ${{ github.token }}
68
+ run: |
69
+ version=$(python -c 'import tomllib; print(tomllib.load(open("Cargo.toml", "rb"))["package"]["version"])')
70
+ # PRs exercise packaging with an available public runtime; source CI
71
+ # validates the unreleased Core independently.
72
+ if [ "$GITHUB_EVENT_NAME" = pull_request ]; then
73
+ tag=$(gh release view --repo "$GITHUB_REPOSITORY" --json tagName --jq .tagName)
74
+ version=${tag#v}
75
+ fi
76
+ echo "version=$version" >> "$GITHUB_OUTPUT"
77
+ echo "image=ghcr.io/${REPOSITORY_OWNER,,}/toolframe" >> "$GITHUB_OUTPUT"
78
+ - name: Download the validated launcher from this publication run
79
+ if: inputs.release_artifacts
80
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
81
+ with:
82
+ name: validated-release
83
+ path: build/candidate/
84
+ - name: Verify the bundle and stage this platform's release
85
+ if: inputs.release_artifacts
86
+ env:
87
+ TOOLFRAME_REPOSITORY_OWNER: ${{ vars.TOOLFRAME_REPOSITORY_OWNER || github.repository_owner }}
88
+ TOOLFRAME_TARGET: ${{ matrix.target }}
89
+ run: >-
90
+ python scripts/ci/artifacts.py export --bundle build/candidate
91
+ --kind release --target "$TOOLFRAME_TARGET" --output build/container-release
92
+ - name: Stage the verified executable
93
+ env:
94
+ USE_ARTIFACTS: ${{ inputs.release_artifacts }}
95
+ ARCH: ${{ matrix.arch }}
96
+ VERSION: ${{ steps.metadata.outputs.version }}
97
+ run: |
98
+ options=()
99
+ if [ "$USE_ARTIFACTS" = true ]; then
100
+ options+=(--release-dir build/container-release)
101
+ fi
102
+ python scripts/prepare-container.py --architecture "$ARCH" --version "$VERSION" \
103
+ --repository "$GITHUB_REPOSITORY" "${options[@]}"
104
+ - name: Build the native image
105
+ env:
106
+ ARCH: ${{ matrix.arch }}
107
+ VARIANT: ${{ matrix.variant }}
108
+ VERSION: ${{ steps.metadata.outputs.version }}
109
+ run: |
110
+ docker buildx build --platform "linux/$ARCH" --target "$VARIANT" \
111
+ --pull --no-cache-filter runtime \
112
+ --build-arg "TOOLFRAME_VERSION=$VERSION" \
113
+ --build-arg "TOOLFRAME_REVISION=$GITHUB_SHA" \
114
+ --label "org.opencontainers.image.source=https://github.com/$GITHUB_REPOSITORY" \
115
+ --provenance=false --load --tag toolframe-check:local .
116
+ - name: Verify public interfaces, persistence and shutdown
117
+ env:
118
+ ARCH: ${{ matrix.arch }}
119
+ VARIANT: ${{ matrix.variant }}
120
+ run: |
121
+ python scripts/verify-container.py --image toolframe-check:local \
122
+ --variant "$VARIANT" --platform "linux/$ARCH" \
123
+ --output build/container-verification.json
124
+ - name: Save verification evidence
125
+ if: always()
126
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
127
+ with:
128
+ name: container-evidence-${{ matrix.variant }}-${{ matrix.arch }}
129
+ path: build/container-verification*
130
+ if-no-files-found: warn
131
+ retention-days: 7
132
+ - name: Scan the tested image before publication
133
+ uses: ./.github/actions/scan-container
134
+ with:
135
+ image: toolframe-check:local
136
+ platform: linux/${{ matrix.arch }}
137
+ image-source: docker
138
+ - name: Save security evidence
139
+ if: always()
140
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
141
+ with:
142
+ name: container-security-${{ matrix.variant }}-${{ matrix.arch }}
143
+ path: build/security/
144
+ if-no-files-found: warn
145
+ retention-days: 7
146
+ - name: Log in to GHCR
147
+ if: inputs.publish
148
+ uses: docker/login-action@783ae9cac559640a24c9212dfa6cd9e998252f9a
149
+ with:
150
+ registry: ghcr.io
151
+ username: ${{ github.actor }}
152
+ password: ${{ secrets.GITHUB_TOKEN }}
153
+ - name: Push the exact locally tested image
154
+ if: inputs.publish
155
+ env:
156
+ IMAGE: ${{ steps.metadata.outputs.image }}
157
+ ARCH: ${{ matrix.arch }}
158
+ VARIANT: ${{ matrix.variant }}
159
+ run: |
160
+ ref="$IMAGE:build-$GITHUB_RUN_ID-$GITHUB_RUN_ATTEMPT-$VARIANT-$ARCH"
161
+ docker tag toolframe-check:local "$ref"
162
+ docker push "$ref"
163
+ mkdir -p build/digests
164
+ docker image inspect --format '{{index .RepoDigests 0}}' "$ref" \
165
+ > "build/digests/$VARIANT-$ARCH.txt"
166
+ - name: Save the tested image digest
167
+ if: inputs.publish
168
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
169
+ with:
170
+ name: container-digest-${{ matrix.variant }}-${{ matrix.arch }}
171
+ path: build/digests/*.txt
172
+ if-no-files-found: error
173
+
174
+ publish:
175
+ name: Publish multi-platform tags
176
+ needs: build
177
+ if: inputs.publish
178
+ runs-on: ubuntu-24.04
179
+ timeout-minutes: 10
180
+ permissions:
181
+ contents: read
182
+ packages: write
183
+ concurrency:
184
+ group: container-publish-${{ github.repository }}
185
+ cancel-in-progress: false
186
+ steps:
187
+ - uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069
188
+ - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
189
+ with:
190
+ pattern: container-digest-*
191
+ merge-multiple: true
192
+ path: build/digests/
193
+ - uses: docker/login-action@783ae9cac559640a24c9212dfa6cd9e998252f9a
194
+ with:
195
+ registry: ghcr.io
196
+ username: ${{ github.actor }}
197
+ password: ${{ secrets.GITHUB_TOKEN }}
198
+ - name: Publish both architectures after all four checks pass
199
+ env:
200
+ IMAGE: ${{ needs.build.outputs.image }}
201
+ VERSION: ${{ needs.build.outputs.version }}
202
+ GH_TOKEN: ${{ github.token }}
203
+ GH_REPO: ${{ github.repository }}
204
+ run: |
205
+ latest=$(gh release view --repo "$GH_REPO" --json tagName --jq .tagName)
206
+ for variant in standard distroless; do
207
+ suffix=""
208
+ alias=latest
209
+ if [ "$variant" = distroless ]; then
210
+ suffix=-distroless
211
+ alias=distroless
212
+ fi
213
+ mapfile -t refs < <(cat build/digests/"$variant"-*.txt)
214
+ test "${#refs[@]}" -eq 2
215
+ tags=(--tag "$IMAGE:$VERSION$suffix")
216
+ if [ "$latest" = "v$VERSION" ] && [[ "$VERSION" != *-* ]]; then
217
+ tags+=(--tag "$IMAGE:$alias")
218
+ fi
219
+ docker buildx imagetools create "${tags[@]}" "${refs[@]}"
220
+ docker buildx imagetools inspect "$IMAGE:$VERSION$suffix"
221
+ done
@@ -76,6 +76,7 @@ jobs:
76
76
  name: launcher-wheel-${{ matrix.target }}
77
77
  path: build/launcher-dist/wheels/*.whl
78
78
  if-no-files-found: error
79
+ overwrite: true
79
80
  retention-days: 14
80
81
  - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
81
82
  with:
@@ -86,6 +87,7 @@ jobs:
86
87
  build/launcher-dist/release/*.json
87
88
  build/launcher-dist/release/SHA256SUMS-*.txt
88
89
  if-no-files-found: error
90
+ overwrite: true
89
91
  retention-days: 14
90
92
  - name: Retain acceptance evidence
91
93
  if: always()
@@ -94,3 +96,4 @@ jobs:
94
96
  name: launcher-evidence-${{ matrix.target }}
95
97
  path: build/launcher-dist/*.json
96
98
  if-no-files-found: warn
99
+ overwrite: true
@@ -0,0 +1,31 @@
1
+ name: Pull request policy
2
+
3
+ on:
4
+ workflow_call:
5
+ # Keep a stable required check for title edits without repeating native CI.
6
+ pull_request:
7
+ types: [opened, synchronize, reopened, edited]
8
+
9
+ permissions:
10
+ contents: read
11
+ pull-requests: read
12
+
13
+ jobs:
14
+ commit-policy:
15
+ name: PR policy
16
+ runs-on: ubuntu-24.04
17
+ timeout-minutes: 10
18
+ steps:
19
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
20
+ with:
21
+ fetch-depth: 0
22
+ persist-credentials: false
23
+ - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
24
+ with:
25
+ python-version: '3.14.7'
26
+ - uses: commit-check/commit-check-action@a61779784a953fd9047c001c102cfeac5cf26964 # commit-check 2.18.3
27
+ with:
28
+ message: true
29
+ branch: false
30
+ pr-title: true
31
+ pr-comments: false
@@ -11,9 +11,15 @@ on:
11
11
  - pypi
12
12
  default: testpypi
13
13
  required: true
14
+ rebuild:
15
+ description: Validate and rebuild at the tag instead of promoting main artifacts
16
+ type: boolean
17
+ default: false
14
18
 
15
19
  permissions:
16
20
  contents: read
21
+ actions: read
22
+ pull-requests: read
17
23
 
18
24
  concurrency:
19
25
  group: publish-${{ github.ref }}-${{ inputs.index }}
@@ -33,9 +39,19 @@ jobs:
33
39
  - name: Require the exact project version tag
34
40
  run: python scripts/ci/check-release.py --ref "$GITHUB_REF"
35
41
 
36
- validate:
42
+ quality:
37
43
  needs: release-tag
44
+ permissions:
45
+ contents: read
46
+ pull-requests: read
47
+ uses: ./.github/workflows/quality.yml
48
+
49
+ validate:
50
+ needs: [release-tag, quality]
38
51
  uses: ./.github/workflows/validate.yml
52
+ with:
53
+ reuse-stage: release
54
+ rebuild: ${{ inputs.rebuild }}
39
55
  secrets: inherit
40
56
 
41
57
  publish-core:
@@ -45,22 +61,24 @@ jobs:
45
61
  environment:
46
62
  name: ${{ inputs.index }}
47
63
  permissions:
64
+ contents: read
48
65
  id-token: write
49
66
  steps:
50
- - name: Download the distributions validated in this run
67
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
68
+ with:
69
+ persist-credentials: false
70
+ - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
71
+ with:
72
+ python-version: '3.14.7'
73
+ - name: Download the bundle validated in this run
51
74
  uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
52
75
  with:
53
- name: python-dist
54
- path: dist/
55
- - name: Require the complete Core release set
56
- run: |
57
- python - <<'PY'
58
- from pathlib import Path
59
- files = list(Path('dist').iterdir())
60
- assert len(list(Path('dist').glob('toolframe_core-*.whl'))) == 1
61
- assert len(list(Path('dist').glob('toolframe_core-*.tar.gz'))) == 1
62
- assert len(files) == 2
63
- PY
76
+ name: validated-release
77
+ path: build/candidate/
78
+ - name: Verify and stage the exact Core distributions
79
+ env:
80
+ TOOLFRAME_REPOSITORY_OWNER: ${{ vars.TOOLFRAME_REPOSITORY_OWNER || github.repository_owner }}
81
+ run: python scripts/ci/artifacts.py export --bundle build/candidate --kind core --output dist
64
82
  - name: Publish Core using its Trusted Publisher
65
83
  uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
66
84
  with:
@@ -74,22 +92,24 @@ jobs:
74
92
  environment:
75
93
  name: ${{ inputs.index }}-launcher
76
94
  permissions:
95
+ contents: read
77
96
  id-token: write
78
97
  steps:
79
- - name: Download all four validated native wheels
98
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
99
+ with:
100
+ persist-credentials: false
101
+ - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
102
+ with:
103
+ python-version: '3.14.7'
104
+ - name: Download the bundle validated in this run
80
105
  uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
81
106
  with:
82
- pattern: launcher-wheel-*
83
- merge-multiple: true
84
- path: dist/
85
- - name: Require the complete launcher release set
86
- run: |
87
- python - <<'PY'
88
- from pathlib import Path
89
- files = list(Path('dist').iterdir())
90
- assert len(list(Path('dist').glob('toolframe-*.whl'))) == 4
91
- assert len(files) == 4
92
- PY
107
+ name: validated-release
108
+ path: build/candidate/
109
+ - name: Verify and stage all four exact native wheels
110
+ env:
111
+ TOOLFRAME_REPOSITORY_OWNER: ${{ vars.TOOLFRAME_REPOSITORY_OWNER || github.repository_owner }}
112
+ run: python scripts/ci/artifacts.py export --bundle build/candidate --kind wheel --output dist
93
113
  - name: Publish the launcher using its Trusted Publisher
94
114
  uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
95
115
  with:
@@ -104,11 +124,20 @@ jobs:
104
124
  permissions:
105
125
  contents: write
106
126
  steps:
127
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
128
+ with:
129
+ persist-credentials: false
130
+ - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
131
+ with:
132
+ python-version: '3.14.7'
107
133
  - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
108
134
  with:
109
- pattern: launcher-release-*
110
- merge-multiple: true
111
- path: releases/
135
+ name: validated-release
136
+ path: build/candidate/
137
+ - name: Verify and stage the exact release archives
138
+ env:
139
+ TOOLFRAME_REPOSITORY_OWNER: ${{ vars.TOOLFRAME_REPOSITORY_OWNER || github.repository_owner }}
140
+ run: python scripts/ci/artifacts.py export --bundle build/candidate --kind release --output releases
112
141
  - name: Publish verified executables and checksums
113
142
  env:
114
143
  GH_TOKEN: ${{ github.token }}
@@ -126,3 +155,14 @@ jobs:
126
155
  EOF
127
156
  gh release create "$RELEASE_TAG" --verify-tag --title "Toolframe $RELEASE_TAG" \
128
157
  --notes-file release-notes.txt releases/*.tar.gz releases/SHA256SUMS releases/manifest-*.json releases/*.whl
158
+
159
+ publish-containers:
160
+ needs: release-binaries
161
+ if: inputs.index == 'pypi'
162
+ permissions:
163
+ contents: read
164
+ packages: write
165
+ uses: ./.github/workflows/container.yml
166
+ with:
167
+ publish: true
168
+ release_artifacts: true
@@ -0,0 +1,49 @@
1
+ name: Code quality
2
+
3
+ on:
4
+ workflow_call:
5
+
6
+ permissions:
7
+ contents: read
8
+
9
+ jobs:
10
+ branch-policy:
11
+ runs-on: ubuntu-24.04
12
+ timeout-minutes: 5
13
+ steps:
14
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
15
+ with:
16
+ persist-credentials: false
17
+ - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
18
+ with:
19
+ python-version: '3.14.7'
20
+ - name: Check the source branch or selected release tag
21
+ env:
22
+ BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
23
+ run: |
24
+ if [ "$GITHUB_REF_TYPE" = tag ]; then
25
+ python scripts/ci/check-release.py --ref "$GITHUB_REF"
26
+ else
27
+ python scripts/check_branch_name.py "$BRANCH_NAME"
28
+ fi
29
+
30
+ code-quality:
31
+ runs-on: ubuntu-24.04
32
+ timeout-minutes: 10
33
+ steps:
34
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
35
+ with:
36
+ persist-credentials: false
37
+ - uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
38
+ with:
39
+ version: '0.12.8'
40
+ enable-cache: false
41
+ - name: Check Python lint and formatting
42
+ run: uvx prek==0.5.5 run ruff-check ruff-format --all-files --show-diff-on-failure
43
+
44
+ commit-policy:
45
+ if: github.event_name == 'pull_request'
46
+ permissions:
47
+ contents: read
48
+ pull-requests: read
49
+ uses: ./.github/workflows/pr-policy.yml