toolframe-core 0.6.2__tar.gz → 0.6.3__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.
- toolframe_core-0.6.3/.dockerignore +15 -0
- toolframe_core-0.6.3/.github/actions/scan-container/action.yml +44 -0
- toolframe_core-0.6.3/.github/dependabot.yml +27 -0
- toolframe_core-0.6.3/.github/workflows/container-security.yml +52 -0
- toolframe_core-0.6.3/.github/workflows/container.yml +213 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/.github/workflows/publish.yml +11 -0
- toolframe_core-0.6.3/.github/workflows/quality.yml +63 -0
- toolframe_core-0.6.3/.pre-commit-config.yaml +29 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/CHANGELOG.md +10 -0
- toolframe_core-0.6.3/CONTRIBUTING.md +47 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/Cargo.lock +1 -1
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/Cargo.toml +1 -1
- toolframe_core-0.6.3/Dockerfile +107 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/PKG-INFO +11 -1
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/README.md +10 -0
- toolframe_core-0.6.3/cchk.toml +10 -0
- toolframe_core-0.6.3/docs/container.md +247 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/docs/postgresql-state.md +1 -1
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/docs/releasing.md +13 -4
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/pyproject.toml +1 -1
- toolframe_core-0.6.3/scripts/check-container-security.py +128 -0
- toolframe_core-0.6.3/scripts/check_branch_name.py +59 -0
- toolframe_core-0.6.3/scripts/container-healthcheck.py +23 -0
- toolframe_core-0.6.3/scripts/harden-container.py +41 -0
- toolframe_core-0.6.3/scripts/prepare-container.py +88 -0
- toolframe_core-0.6.3/scripts/verify-container.py +335 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/src/main.rs +8 -8
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/src/toolframe_core/__init__.py +1 -1
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/src/toolframe_core/api.py +1 -0
- toolframe_core-0.6.3/tests/test_container_release.py +98 -0
- toolframe_core-0.6.3/tests/test_container_security.py +105 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/tests/test_core_state.py +1 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/uv.lock +1 -1
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/.github/workflows/ci.yml +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/.github/workflows/launcher.yml +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/.github/workflows/validate.yml +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/.gitignore +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/LICENSE +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/NOTICE +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/companion-wheels.txt +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/docs/adr/0001-explicit-dashboard-access-mode.md +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/docs/adr/0002-scoped-passwords-and-public-business-entrances.md +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/docs/adr/0003-public-fallback-on-auth-error-or-disablement.md +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/docs/adr/0004-separate-auth-ownership-from-dashboard-presentation.md +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/docs/adr/0005-password-only-login-and-secret-reuse.md +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/docs/adr/0006-require-explicit-plugin-authorization-contracts.md +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/docs/adr/0007-independent-mcp-bearer-authentication.md +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/docs/adr/0008-shared-oidc-authentication.md +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/docs/adr/0009-replaceable-core-journal.md +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/docs/adr/0010-multiple-sql-providers.md +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/docs/adr/0011-safe-new-application-access.md +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/docs/adr/0012-optional-runtime-tracing.md +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/docs/adr/0013-context-logging.md +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/docs/architecture.md +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/docs/authentication.md +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/docs/ci.md +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/docs/dependency-graph.md +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/docs/glossary.md +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/docs/mcp-authentication.md +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/docs/object-storage.md +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/docs/offline-maintenance.md +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/docs/oidc-authentication.md +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/docs/runtime.md +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/docs/sql-storage.md +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/docs/testing.md +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/docs/tracing.md +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/packaging/launcher/NOTICE +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/packaging/launcher/README.md +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/packaging/launcher/pyproject.toml +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/scripts/build-launcher.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/scripts/build-release.sh +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/scripts/ci/check-launcher-wheel.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/scripts/ci/check-postgres.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/scripts/ci/check-release.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/scripts/ci/dependencies.json +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/scripts/ci/prepare-launcher.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/scripts/ci/validate.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/scripts/dev-wheelhouse.sh +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/scripts/verify-auth-upgrade.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/scripts/verify-auth.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/scripts/verify-dependencies.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/scripts/verify-network.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/scripts/verify-operation-history.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/scripts/verify-release.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/scripts/verify-retained-plugins.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/scripts/verify-scaffold.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/scripts/verify-skill.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/src/companions.rs +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/src/toolframe_core/_state_postgres.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/src/toolframe_core/_state_sqlite.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/src/toolframe_core/access.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/src/toolframe_core/bundled_skills/toolframe-plugin-design/LICENSE +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/src/toolframe_core/bundled_skills/toolframe-plugin-design/SKILL.md +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/src/toolframe_core/bundled_skills/toolframe-plugin-design/agents/openai.yaml +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/src/toolframe_core/bundled_skills/toolframe-plugin-design/assets/sample-plugin/LICENSE +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/src/toolframe_core/bundled_skills/toolframe-plugin-design/assets/sample-plugin/pyproject.toml +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/src/toolframe_core/bundled_skills/toolframe-plugin-design/assets/sample-plugin/src/toolframe_sample_notes/__init__.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/src/toolframe_core/bundled_skills/toolframe-plugin-design/assets/sample-plugin/src/toolframe_sample_notes/docs/usage.md +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/src/toolframe_core/bundled_skills/toolframe-plugin-design/assets/sample-plugin/src/toolframe_sample_notes/migrations/0001_init.sql +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/src/toolframe_core/bundled_skills/toolframe-plugin-design/assets/sample-plugin/src/toolframe_sample_notes/page.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/src/toolframe_core/bundled_skills/toolframe-plugin-design/assets/sample-plugin/src/toolframe_sample_notes/plugin.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/src/toolframe_core/bundled_skills/toolframe-plugin-design/assets/sample-plugin/src/toolframe_sample_notes/service.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/src/toolframe_core/bundled_skills/toolframe-plugin-design/evals/cases.json +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/src/toolframe_core/bundled_skills/toolframe-plugin-design/references/design.md +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/src/toolframe_core/bundled_skills/toolframe-plugin-design/references/operations.md +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/src/toolframe_core/bundled_skills/toolframe-plugin-design/references/plugin-api.md +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/src/toolframe_core/cli.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/src/toolframe_core/config.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/src/toolframe_core/diagnostics.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/src/toolframe_core/graph.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/src/toolframe_core/host.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/src/toolframe_core/maintenance.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/src/toolframe_core/mcp_access.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/src/toolframe_core/network.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/src/toolframe_core/oidc_access.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/src/toolframe_core/packages.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/src/toolframe_core/process.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/src/toolframe_core/redaction.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/src/toolframe_core/scaffold.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/src/toolframe_core/skills.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/src/toolframe_core/state.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/src/toolframe_core/state_admin.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/src/toolframe_core/stores.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/src/toolframe_core/templates.json +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/src/toolframe_core/templates.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/src/uv.rs +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/tests/test_acceptance.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/tests/test_access_policy.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/tests/test_architecture.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/tests/test_auth.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/tests/test_bundles.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/tests/test_cli.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/tests/test_diagnostics.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/tests/test_foundations.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/tests/test_host.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/tests/test_maintenance.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/tests/test_managed_tasks.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/tests/test_mcp_auth.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/tests/test_mixed_storage.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/tests/test_network.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/tests/test_object_store.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/tests/test_oidc.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/tests/test_operation_history.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/tests/test_process.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/tests/test_redaction.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/tests/test_retained_plugins.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/tests/test_scaffold.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/tests/test_skills.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/tests/test_storage_bindings.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/tests/test_tracing.py +0 -0
- {toolframe_core-0.6.2 → toolframe_core-0.6.3}/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,27 @@
|
|
|
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
|
+
ignore:
|
|
14
|
+
# The 0.6.3 launcher accepts uv >=0.12.2,<0.13.0.
|
|
15
|
+
# Widen this only alongside a compatible launcher release.
|
|
16
|
+
- dependency-name: astral-sh/uv
|
|
17
|
+
versions: ['>=0.13.0']
|
|
18
|
+
- package-ecosystem: github-actions
|
|
19
|
+
directory: /
|
|
20
|
+
schedule:
|
|
21
|
+
interval: weekly
|
|
22
|
+
day: monday
|
|
23
|
+
time: '04:23'
|
|
24
|
+
timezone: Etc/UTC
|
|
25
|
+
open-pull-requests-limit: 4
|
|
26
|
+
commit-message:
|
|
27
|
+
prefix: chore(ci)
|
|
@@ -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,213 @@
|
|
|
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: launcher-release-${{ matrix.target }}
|
|
83
|
+
path: build/container-release/
|
|
84
|
+
- name: Stage the verified executable
|
|
85
|
+
env:
|
|
86
|
+
USE_ARTIFACTS: ${{ inputs.release_artifacts }}
|
|
87
|
+
ARCH: ${{ matrix.arch }}
|
|
88
|
+
VERSION: ${{ steps.metadata.outputs.version }}
|
|
89
|
+
run: |
|
|
90
|
+
options=()
|
|
91
|
+
if [ "$USE_ARTIFACTS" = true ]; then
|
|
92
|
+
options+=(--release-dir build/container-release)
|
|
93
|
+
fi
|
|
94
|
+
python scripts/prepare-container.py --architecture "$ARCH" --version "$VERSION" \
|
|
95
|
+
--repository "$GITHUB_REPOSITORY" "${options[@]}"
|
|
96
|
+
- name: Build the native image
|
|
97
|
+
env:
|
|
98
|
+
ARCH: ${{ matrix.arch }}
|
|
99
|
+
VARIANT: ${{ matrix.variant }}
|
|
100
|
+
VERSION: ${{ steps.metadata.outputs.version }}
|
|
101
|
+
run: |
|
|
102
|
+
docker buildx build --platform "linux/$ARCH" --target "$VARIANT" \
|
|
103
|
+
--pull --no-cache-filter runtime \
|
|
104
|
+
--build-arg "TOOLFRAME_VERSION=$VERSION" \
|
|
105
|
+
--build-arg "TOOLFRAME_REVISION=$GITHUB_SHA" \
|
|
106
|
+
--label "org.opencontainers.image.source=https://github.com/$GITHUB_REPOSITORY" \
|
|
107
|
+
--provenance=false --load --tag toolframe-check:local .
|
|
108
|
+
- name: Verify public interfaces, persistence and shutdown
|
|
109
|
+
env:
|
|
110
|
+
ARCH: ${{ matrix.arch }}
|
|
111
|
+
VARIANT: ${{ matrix.variant }}
|
|
112
|
+
run: |
|
|
113
|
+
python scripts/verify-container.py --image toolframe-check:local \
|
|
114
|
+
--variant "$VARIANT" --platform "linux/$ARCH" \
|
|
115
|
+
--output build/container-verification.json
|
|
116
|
+
- name: Save verification evidence
|
|
117
|
+
if: always()
|
|
118
|
+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
119
|
+
with:
|
|
120
|
+
name: container-evidence-${{ matrix.variant }}-${{ matrix.arch }}
|
|
121
|
+
path: build/container-verification*
|
|
122
|
+
if-no-files-found: warn
|
|
123
|
+
retention-days: 7
|
|
124
|
+
- name: Scan the tested image before publication
|
|
125
|
+
uses: ./.github/actions/scan-container
|
|
126
|
+
with:
|
|
127
|
+
image: toolframe-check:local
|
|
128
|
+
platform: linux/${{ matrix.arch }}
|
|
129
|
+
image-source: docker
|
|
130
|
+
- name: Save security evidence
|
|
131
|
+
if: always()
|
|
132
|
+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
133
|
+
with:
|
|
134
|
+
name: container-security-${{ matrix.variant }}-${{ matrix.arch }}
|
|
135
|
+
path: build/security/
|
|
136
|
+
if-no-files-found: warn
|
|
137
|
+
retention-days: 7
|
|
138
|
+
- name: Log in to GHCR
|
|
139
|
+
if: inputs.publish
|
|
140
|
+
uses: docker/login-action@783ae9cac559640a24c9212dfa6cd9e998252f9a
|
|
141
|
+
with:
|
|
142
|
+
registry: ghcr.io
|
|
143
|
+
username: ${{ github.actor }}
|
|
144
|
+
password: ${{ secrets.GITHUB_TOKEN }}
|
|
145
|
+
- name: Push the exact locally tested image
|
|
146
|
+
if: inputs.publish
|
|
147
|
+
env:
|
|
148
|
+
IMAGE: ${{ steps.metadata.outputs.image }}
|
|
149
|
+
ARCH: ${{ matrix.arch }}
|
|
150
|
+
VARIANT: ${{ matrix.variant }}
|
|
151
|
+
run: |
|
|
152
|
+
ref="$IMAGE:build-$GITHUB_RUN_ID-$GITHUB_RUN_ATTEMPT-$VARIANT-$ARCH"
|
|
153
|
+
docker tag toolframe-check:local "$ref"
|
|
154
|
+
docker push "$ref"
|
|
155
|
+
mkdir -p build/digests
|
|
156
|
+
docker image inspect --format '{{index .RepoDigests 0}}' "$ref" \
|
|
157
|
+
> "build/digests/$VARIANT-$ARCH.txt"
|
|
158
|
+
- name: Save the tested image digest
|
|
159
|
+
if: inputs.publish
|
|
160
|
+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
161
|
+
with:
|
|
162
|
+
name: container-digest-${{ matrix.variant }}-${{ matrix.arch }}
|
|
163
|
+
path: build/digests/*.txt
|
|
164
|
+
if-no-files-found: error
|
|
165
|
+
|
|
166
|
+
publish:
|
|
167
|
+
name: Publish multi-platform tags
|
|
168
|
+
needs: build
|
|
169
|
+
if: inputs.publish
|
|
170
|
+
runs-on: ubuntu-24.04
|
|
171
|
+
timeout-minutes: 10
|
|
172
|
+
permissions:
|
|
173
|
+
contents: read
|
|
174
|
+
packages: write
|
|
175
|
+
concurrency:
|
|
176
|
+
group: container-publish-${{ github.repository }}
|
|
177
|
+
cancel-in-progress: false
|
|
178
|
+
steps:
|
|
179
|
+
- uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069
|
|
180
|
+
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
|
181
|
+
with:
|
|
182
|
+
pattern: container-digest-*
|
|
183
|
+
merge-multiple: true
|
|
184
|
+
path: build/digests/
|
|
185
|
+
- uses: docker/login-action@783ae9cac559640a24c9212dfa6cd9e998252f9a
|
|
186
|
+
with:
|
|
187
|
+
registry: ghcr.io
|
|
188
|
+
username: ${{ github.actor }}
|
|
189
|
+
password: ${{ secrets.GITHUB_TOKEN }}
|
|
190
|
+
- name: Publish both architectures after all four checks pass
|
|
191
|
+
env:
|
|
192
|
+
IMAGE: ${{ needs.build.outputs.image }}
|
|
193
|
+
VERSION: ${{ needs.build.outputs.version }}
|
|
194
|
+
GH_TOKEN: ${{ github.token }}
|
|
195
|
+
GH_REPO: ${{ github.repository }}
|
|
196
|
+
run: |
|
|
197
|
+
latest=$(gh release view --repo "$GH_REPO" --json tagName --jq .tagName)
|
|
198
|
+
for variant in standard distroless; do
|
|
199
|
+
suffix=""
|
|
200
|
+
alias=latest
|
|
201
|
+
if [ "$variant" = distroless ]; then
|
|
202
|
+
suffix=-distroless
|
|
203
|
+
alias=distroless
|
|
204
|
+
fi
|
|
205
|
+
mapfile -t refs < <(cat build/digests/"$variant"-*.txt)
|
|
206
|
+
test "${#refs[@]}" -eq 2
|
|
207
|
+
tags=(--tag "$IMAGE:$VERSION$suffix")
|
|
208
|
+
if [ "$latest" = "v$VERSION" ] && [[ "$VERSION" != *-* ]]; then
|
|
209
|
+
tags+=(--tag "$IMAGE:$alias")
|
|
210
|
+
fi
|
|
211
|
+
docker buildx imagetools create "${tags[@]}" "${refs[@]}"
|
|
212
|
+
docker buildx imagetools inspect "$IMAGE:$VERSION$suffix"
|
|
213
|
+
done
|
|
@@ -126,3 +126,14 @@ jobs:
|
|
|
126
126
|
EOF
|
|
127
127
|
gh release create "$RELEASE_TAG" --verify-tag --title "Toolframe $RELEASE_TAG" \
|
|
128
128
|
--notes-file release-notes.txt releases/*.tar.gz releases/SHA256SUMS releases/manifest-*.json releases/*.whl
|
|
129
|
+
|
|
130
|
+
publish-containers:
|
|
131
|
+
needs: release-binaries
|
|
132
|
+
if: inputs.index == 'pypi'
|
|
133
|
+
permissions:
|
|
134
|
+
contents: read
|
|
135
|
+
packages: write
|
|
136
|
+
uses: ./.github/workflows/container.yml
|
|
137
|
+
with:
|
|
138
|
+
publish: true
|
|
139
|
+
release_artifacts: true
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
name: Code quality
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: ['**']
|
|
6
|
+
pull_request:
|
|
7
|
+
types: [opened, synchronize, reopened, edited]
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
|
|
10
|
+
permissions:
|
|
11
|
+
contents: read
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
branch-policy:
|
|
15
|
+
runs-on: ubuntu-24.04
|
|
16
|
+
timeout-minutes: 5
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
19
|
+
with:
|
|
20
|
+
persist-credentials: false
|
|
21
|
+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
22
|
+
with:
|
|
23
|
+
python-version: '3.14.7'
|
|
24
|
+
- name: Check the actual source branch
|
|
25
|
+
env:
|
|
26
|
+
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
|
|
27
|
+
run: python scripts/check_branch_name.py "$BRANCH_NAME"
|
|
28
|
+
|
|
29
|
+
code-quality:
|
|
30
|
+
runs-on: ubuntu-24.04
|
|
31
|
+
timeout-minutes: 10
|
|
32
|
+
steps:
|
|
33
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
34
|
+
with:
|
|
35
|
+
persist-credentials: false
|
|
36
|
+
- uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
|
|
37
|
+
with:
|
|
38
|
+
version: '0.12.8'
|
|
39
|
+
enable-cache: false
|
|
40
|
+
- name: Check Python lint and formatting
|
|
41
|
+
run: uvx prek==0.5.5 run ruff-check ruff-format --all-files --show-diff-on-failure
|
|
42
|
+
|
|
43
|
+
commit-policy:
|
|
44
|
+
if: github.event_name == 'pull_request'
|
|
45
|
+
runs-on: ubuntu-24.04
|
|
46
|
+
timeout-minutes: 10
|
|
47
|
+
permissions:
|
|
48
|
+
contents: read
|
|
49
|
+
pull-requests: read
|
|
50
|
+
steps:
|
|
51
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
52
|
+
with:
|
|
53
|
+
fetch-depth: 0
|
|
54
|
+
persist-credentials: false
|
|
55
|
+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
56
|
+
with:
|
|
57
|
+
python-version: '3.14.7'
|
|
58
|
+
- uses: commit-check/commit-check-action@a61779784a953fd9047c001c102cfeac5cf26964 # commit-check 2.18.3
|
|
59
|
+
with:
|
|
60
|
+
message: true
|
|
61
|
+
branch: false
|
|
62
|
+
pr-title: true
|
|
63
|
+
pr-comments: false
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
default_install_hook_types: [pre-commit, commit-msg]
|
|
2
|
+
default_stages: [pre-commit]
|
|
3
|
+
default_language_version:
|
|
4
|
+
python: python3.11
|
|
5
|
+
|
|
6
|
+
repos:
|
|
7
|
+
- repo: local
|
|
8
|
+
hooks:
|
|
9
|
+
- id: check-branch-name
|
|
10
|
+
name: Check branch naming policy
|
|
11
|
+
entry: python scripts/check_branch_name.py
|
|
12
|
+
language: python
|
|
13
|
+
always_run: true
|
|
14
|
+
pass_filenames: false
|
|
15
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
16
|
+
rev: v0.16.8
|
|
17
|
+
hooks:
|
|
18
|
+
- id: ruff-check
|
|
19
|
+
types_or: [python, pyi]
|
|
20
|
+
files: '^(src/|tests/|scripts/(build-launcher\.py$|verify-release\.py$|verify-skill\.py$|check_branch_name\.py$|ci/))'
|
|
21
|
+
- id: ruff-format
|
|
22
|
+
types_or: [python, pyi]
|
|
23
|
+
args: [--check]
|
|
24
|
+
files: '^(src/|tests/|scripts/(build-launcher\.py$|verify-release\.py$|verify-skill\.py$|check_branch_name\.py$|ci/))'
|
|
25
|
+
- repo: https://github.com/commit-check/commit-check
|
|
26
|
+
rev: v2.18.3
|
|
27
|
+
hooks:
|
|
28
|
+
- id: check-message
|
|
29
|
+
stages: [commit-msg]
|
|
@@ -5,6 +5,16 @@ imply that its distributions have been published or every target is qualified.
|
|
|
5
5
|
|
|
6
6
|
## Unreleased
|
|
7
7
|
|
|
8
|
+
## 0.6.3
|
|
9
|
+
|
|
10
|
+
- Apply container security updates, remove unused pip bootstrap dependencies and
|
|
11
|
+
privileged executable bits, and gate publication on vulnerability scans with
|
|
12
|
+
daily image checks and weekly dependency update proposals.
|
|
13
|
+
|
|
14
|
+
## 0.6.2
|
|
15
|
+
|
|
16
|
+
- Add Debian and Distroless container images with prepared Core runtimes, Tini,
|
|
17
|
+
persistent application volumes and verified multi-platform GHCR publication.
|
|
8
18
|
- Run multiple SQL storage providers using service defaults and per-plugin bindings.
|
|
9
19
|
- Retain store provider ownership across removal and restart; reject silent rebinding.
|
|
10
20
|
- Bind migration plans and forward repair to their provider, and preserve admitted
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
## Commit hooks
|
|
4
|
+
|
|
5
|
+
Install [prek](https://prek.j178.dev/) and enable the repository's hooks:
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
uv tool install prek==0.5.5
|
|
9
|
+
prek install --allow-missing-config
|
|
10
|
+
prek run --all-files
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
The missing-config option allows older worktrees without this configuration to
|
|
14
|
+
keep working. Worktrees containing `.pre-commit-config.yaml` still run the checks.
|
|
15
|
+
The `pre-commit` hook checks the branch name, Python lint, and formatting. The
|
|
16
|
+
`commit-msg` hook checks Conventional Commits. Both Ruff hooks only check files;
|
|
17
|
+
they do not rewrite a commit's contents. Fix lint and formatting explicitly:
|
|
18
|
+
|
|
19
|
+
```sh
|
|
20
|
+
uvx ruff==0.16.8 check --fix src tests scripts/build-launcher.py scripts/verify-release.py scripts/verify-skill.py scripts/ci scripts/check_branch_name.py
|
|
21
|
+
uvx ruff==0.16.8 format src tests scripts/build-launcher.py scripts/verify-release.py scripts/verify-skill.py scripts/ci scripts/check_branch_name.py
|
|
22
|
+
prek run --all-files
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
The Ruff version and checked paths are pinned in
|
|
26
|
+
[the hook configuration](.pre-commit-config.yaml); the Python rules remain in
|
|
27
|
+
[pyproject.toml](pyproject.toml). CI uses these same hooks on all tracked files
|
|
28
|
+
within their configured paths. Existing package, integration, and release checks
|
|
29
|
+
run independently.
|
|
30
|
+
|
|
31
|
+
## Branches and commits
|
|
32
|
+
|
|
33
|
+
[cchk.toml](cchk.toml) defines the allowed branch and commit types. Work branches
|
|
34
|
+
use `feat/`, `fix/`, `release/`, or `chore/`, followed by lowercase ASCII letters
|
|
35
|
+
and digits separated by single hyphens. Release versions may also contain dots,
|
|
36
|
+
as in `release/v1.2.0-rc.1`; every separator must have an alphanumeric character on
|
|
37
|
+
both sides. The default branch `main` is the standalone exception.
|
|
38
|
+
|
|
39
|
+
Commit types are independent of branch types: for example,
|
|
40
|
+
`docs: clarify setup` is valid on `chore/update-docs`. Commit-check uses Conventional
|
|
41
|
+
Commits with its default subject length of 5–80 characters. Pull requests check
|
|
42
|
+
their commits and title so the title can be used for a Conventional Commit when
|
|
43
|
+
squash merging.
|
|
44
|
+
|
|
45
|
+
Local hooks can be bypassed. CI reports `branch-policy`, `code-quality`, and
|
|
46
|
+
`commit-policy`; maintainers must configure required status checks separately to
|
|
47
|
+
make passing checks a merge requirement.
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# syntax=docker/dockerfile:1
|
|
2
|
+
FROM ghcr.io/astral-sh/uv:0.12.24@sha256:3af4716e991d6956a41e573eab705d0ee08500cd829ed30293eb8472f372c65a AS uv
|
|
3
|
+
|
|
4
|
+
FROM debian:trixie-slim@sha256:a29215f6a35e51e22adffa17f89e9d2ef06214e64a2bad10d765c46aea49f11f AS runtime
|
|
5
|
+
ARG TARGETARCH
|
|
6
|
+
ARG TOOLFRAME_VERSION=0.6.3
|
|
7
|
+
ARG TOOLFRAME_REVISION
|
|
8
|
+
LABEL org.opencontainers.image.source="https://github.com/toolframe/toolframe-core" \
|
|
9
|
+
org.opencontainers.image.title="Toolframe" \
|
|
10
|
+
org.opencontainers.image.description="Persistent control host for Python plugins" \
|
|
11
|
+
org.opencontainers.image.licenses="Apache-2.0 AND MIT" \
|
|
12
|
+
org.opencontainers.image.version="${TOOLFRAME_VERSION}" \
|
|
13
|
+
org.opencontainers.image.revision="${TOOLFRAME_REVISION}"
|
|
14
|
+
RUN apt-get update \
|
|
15
|
+
&& apt-get upgrade -y --no-install-recommends \
|
|
16
|
+
&& apt-get install -y --no-install-recommends ca-certificates git libstdc++6 procps tini \
|
|
17
|
+
&& rm -rf /var/lib/apt/lists/* \
|
|
18
|
+
&& find /usr -xdev -type f -perm /6000 -exec chmod a-s '{}' + \
|
|
19
|
+
&& groupadd --gid 65532 nonroot \
|
|
20
|
+
&& useradd --uid 65532 --gid 65532 --create-home --home-dir /home/nonroot nonroot \
|
|
21
|
+
&& install -d -o 65532 -g 65532 /data /opt/toolframe
|
|
22
|
+
COPY --from=uv /uv /usr/local/bin/uv
|
|
23
|
+
# prepare-container.py verifies the release checksums before staging these files.
|
|
24
|
+
COPY build/container/${TARGETARCH}/toolframe /usr/local/bin/toolframe
|
|
25
|
+
COPY build/container/${TARGETARCH}/LICENSE build/container/${TARGETARCH}/NOTICE /usr/share/doc/toolframe/
|
|
26
|
+
COPY scripts/container-healthcheck.py /usr/local/lib/toolframe/healthcheck.py
|
|
27
|
+
COPY scripts/harden-container.py /usr/local/lib/toolframe/harden.py
|
|
28
|
+
ENV HOME=/home/nonroot \
|
|
29
|
+
TOOLFRAME_UV=/usr/local/bin/uv \
|
|
30
|
+
TOOLFRAME_RUNTIME_ROOT=/opt/toolframe/runtime \
|
|
31
|
+
UV_PYTHON_INSTALL_DIR=/opt/toolframe/python \
|
|
32
|
+
UV_CACHE_DIR=/data/.toolframe/uv-cache \
|
|
33
|
+
UV_LINK_MODE=copy \
|
|
34
|
+
PYTHONUNBUFFERED=1 \
|
|
35
|
+
PYTHONDONTWRITEBYTECODE=1
|
|
36
|
+
USER 65532:65532
|
|
37
|
+
WORKDIR /data
|
|
38
|
+
# --help prepares Core without creating an application, keys or management tokens.
|
|
39
|
+
# Keep the same absolute Python and venv paths in both final images.
|
|
40
|
+
RUN test "$(toolframe --version)" = "toolframe ${TOOLFRAME_VERSION}" \
|
|
41
|
+
&& UV_CACHE_DIR=/tmp/uv-build-cache toolframe --help > /dev/null \
|
|
42
|
+
&& ln -s "$(uv python find --managed-python 3.14.7)" /opt/toolframe/python3 \
|
|
43
|
+
&& UV_CACHE_DIR=/tmp/uv-build-cache uv cache clean \
|
|
44
|
+
&& /opt/toolframe/python3 /usr/local/lib/toolframe/harden.py
|
|
45
|
+
VOLUME ["/data"]
|
|
46
|
+
EXPOSE 9876
|
|
47
|
+
STOPSIGNAL SIGTERM
|
|
48
|
+
HEALTHCHECK --interval=30s --timeout=5s --start-period=60s \
|
|
49
|
+
CMD ["/opt/toolframe/python3", "/usr/local/lib/toolframe/healthcheck.py"]
|
|
50
|
+
ENTRYPOINT ["/usr/bin/tini", "--", "/usr/local/bin/toolframe", "--home", "/data"]
|
|
51
|
+
CMD ["serve", "--host", "0.0.0.0"]
|
|
52
|
+
|
|
53
|
+
FROM runtime AS ps-dependencies
|
|
54
|
+
USER root
|
|
55
|
+
# Core uses ps to reconcile worker ownership. Retain the final base's libc and
|
|
56
|
+
# loader, and copy only ps's additional shared libraries under their SONAMEs.
|
|
57
|
+
# Include dpkg status fragments so scanners can identify these copied components.
|
|
58
|
+
RUN mkdir -p /opt/ps-libs/var/lib/dpkg/status.d \
|
|
59
|
+
&& ldd /usr/bin/ps | awk '/=> \// { print $3 }' | while read -r library; do \
|
|
60
|
+
case "$library" in */libc.so.*|*/libm.so.*) continue ;; esac; \
|
|
61
|
+
directory=$(dirname "$(readlink -f "$library")"); \
|
|
62
|
+
install -D "$library" "/opt/ps-libs$directory/$(basename "$library")"; \
|
|
63
|
+
package=$(dpkg-query -S "$(readlink -f "$library")") || exit 1; \
|
|
64
|
+
package=${package%%:*}; \
|
|
65
|
+
dpkg-query -s "$package" > "/opt/ps-libs/var/lib/dpkg/status.d/$package" || exit 1; \
|
|
66
|
+
done \
|
|
67
|
+
&& dpkg-query -s procps > /opt/ps-libs/var/lib/dpkg/status.d/procps \
|
|
68
|
+
&& dpkg-query -s tini > /opt/ps-libs/var/lib/dpkg/status.d/tini
|
|
69
|
+
|
|
70
|
+
FROM gcr.io/distroless/cc-debian13:nonroot@sha256:e792ab3d241a468a4fd7519ddbbebe66b49b5f365771716ea688ad40b6c6f1c2 AS distroless
|
|
71
|
+
ARG TOOLFRAME_VERSION=0.6.3
|
|
72
|
+
ARG TOOLFRAME_REVISION
|
|
73
|
+
LABEL org.opencontainers.image.source="https://github.com/toolframe/toolframe-core" \
|
|
74
|
+
org.opencontainers.image.title="Toolframe (Distroless)" \
|
|
75
|
+
org.opencontainers.image.description="Persistent control host for Python plugins, without a system shell" \
|
|
76
|
+
org.opencontainers.image.licenses="Apache-2.0 AND MIT" \
|
|
77
|
+
org.opencontainers.image.version="${TOOLFRAME_VERSION}" \
|
|
78
|
+
org.opencontainers.image.revision="${TOOLFRAME_REVISION}"
|
|
79
|
+
COPY --from=runtime /usr/local/bin/toolframe /usr/local/bin/uv /usr/local/bin/
|
|
80
|
+
COPY --from=runtime /usr/bin/tini /usr/bin/tini
|
|
81
|
+
COPY --from=runtime /usr/bin/ps /usr/bin/ps
|
|
82
|
+
COPY --from=ps-dependencies /opt/ps-libs/ /
|
|
83
|
+
COPY --from=runtime /usr/share/doc/ /usr/share/doc/
|
|
84
|
+
COPY --from=runtime /usr/local/lib/toolframe/ /usr/local/lib/toolframe/
|
|
85
|
+
COPY --from=runtime --chown=65532:65532 /opt/toolframe/ /opt/toolframe/
|
|
86
|
+
COPY --from=runtime --chown=65532:65532 /home/nonroot/ /home/nonroot/
|
|
87
|
+
COPY --from=runtime --chown=65532:65532 /data/ /data/
|
|
88
|
+
ENV HOME=/home/nonroot \
|
|
89
|
+
TOOLFRAME_UV=/usr/local/bin/uv \
|
|
90
|
+
TOOLFRAME_RUNTIME_ROOT=/opt/toolframe/runtime \
|
|
91
|
+
UV_PYTHON_INSTALL_DIR=/opt/toolframe/python \
|
|
92
|
+
UV_CACHE_DIR=/data/.toolframe/uv-cache \
|
|
93
|
+
UV_LINK_MODE=copy \
|
|
94
|
+
PYTHONUNBUFFERED=1 \
|
|
95
|
+
PYTHONDONTWRITEBYTECODE=1
|
|
96
|
+
USER 65532:65532
|
|
97
|
+
WORKDIR /data
|
|
98
|
+
VOLUME ["/data"]
|
|
99
|
+
EXPOSE 9876
|
|
100
|
+
STOPSIGNAL SIGTERM
|
|
101
|
+
HEALTHCHECK --interval=30s --timeout=5s --start-period=60s \
|
|
102
|
+
CMD ["/opt/toolframe/python3", "/usr/local/lib/toolframe/healthcheck.py"]
|
|
103
|
+
ENTRYPOINT ["/usr/bin/tini", "--", "/usr/local/bin/toolframe", "--home", "/data"]
|
|
104
|
+
CMD ["serve", "--host", "0.0.0.0"]
|
|
105
|
+
|
|
106
|
+
# The default build target is the Debian image.
|
|
107
|
+
FROM runtime AS standard
|