codapact 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.
- codapact-0.1.0/.github/workflows/ci.yml +53 -0
- codapact-0.1.0/.github/workflows/mutation-alerts.yml +73 -0
- codapact-0.1.0/.github/workflows/mutation.yml +55 -0
- codapact-0.1.0/.github/workflows/release.yml +88 -0
- codapact-0.1.0/.release-please-manifest.json +1 -0
- codapact-0.1.0/CHANGELOG.md +14 -0
- codapact-0.1.0/LICENSE +21 -0
- codapact-0.1.0/PKG-INFO +62 -0
- codapact-0.1.0/README.md +47 -0
- codapact-0.1.0/branding/mark.svg +8 -0
- codapact-0.1.0/branding/wordmark.svg +11 -0
- codapact-0.1.0/docs/architecture.md +74 -0
- codapact-0.1.0/docs/branding.md +25 -0
- codapact-0.1.0/docs/configuration.md +167 -0
- codapact-0.1.0/docs/mutation.md +71 -0
- codapact-0.1.0/docs/releasing.md +41 -0
- codapact-0.1.0/docs/support.md +69 -0
- codapact-0.1.0/docs/verification.md +59 -0
- codapact-0.1.0/examples/cli.json +4 -0
- codapact-0.1.0/examples/pets.codapact.yaml +18 -0
- codapact-0.1.0/examples/pets.yaml +43 -0
- codapact-0.1.0/examples/runtime.json +5 -0
- codapact-0.1.0/pyproject.toml +141 -0
- codapact-0.1.0/pyproject.toml.orig +75 -0
- codapact-0.1.0/release-please-config.json +31 -0
- codapact-0.1.0/schemas/cli.v1.schema.json +23 -0
- codapact-0.1.0/scripts/mutation_alerts.py +384 -0
- codapact-0.1.0/scripts/mutation_report.py +110 -0
- codapact-0.1.0/scripts/verify_dist.py +35 -0
- codapact-0.1.0/src/codapact/__init__.py +3 -0
- codapact-0.1.0/src/codapact/__main__.py +83 -0
- codapact-0.1.0/src/codapact/cli.py +117 -0
- codapact-0.1.0/src/codapact/configuration.py +135 -0
- codapact-0.1.0/src/codapact/errors.py +30 -0
- codapact-0.1.0/src/codapact/generation.py +243 -0
- codapact-0.1.0/src/codapact/loading.py +121 -0
- codapact-0.1.0/src/codapact/model.py +83 -0
- codapact-0.1.0/src/codapact/net.py +100 -0
- codapact-0.1.0/src/codapact/openapi.py +294 -0
- codapact-0.1.0/src/codapact/profiles.py +171 -0
- codapact-0.1.0/src/codapact/project.py +173 -0
- codapact-0.1.0/src/codapact/py.typed +0 -0
- codapact-0.1.0/src/codapact/runtime.py +299 -0
- codapact-0.1.0/src/codapact/schemas/generation.v1.json +57 -0
- codapact-0.1.0/src/codapact/values.py +33 -0
- codapact-0.1.0/tests/conftest.py +170 -0
- codapact-0.1.0/tests/test_adversarial.py +140 -0
- codapact-0.1.0/tests/test_configuration.py +421 -0
- codapact-0.1.0/tests/test_distribution.py +104 -0
- codapact-0.1.0/tests/test_entrypoint.py +41 -0
- codapact-0.1.0/tests/test_generation.py +220 -0
- codapact-0.1.0/tests/test_loading.py +82 -0
- codapact-0.1.0/tests/test_mutation_alerts.py +277 -0
- codapact-0.1.0/tests/test_net.py +100 -0
- codapact-0.1.0/tests/test_openapi.py +84 -0
- codapact-0.1.0/tests/test_runtime.py +230 -0
- codapact-0.1.0/uv.lock +1239 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
on:
|
|
3
|
+
pull_request:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
workflow_call:
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
jobs:
|
|
11
|
+
title:
|
|
12
|
+
name: Conventional PR title
|
|
13
|
+
if: github.event_name == 'pull_request'
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- name: Check title
|
|
17
|
+
env:
|
|
18
|
+
TITLE: ${{ github.event.pull_request.title }}
|
|
19
|
+
run: |
|
|
20
|
+
pattern='^(feat|fix|perf|docs|build|ci|refactor|test|chore|style|revert)(\([^)]+\))?!?: .+'
|
|
21
|
+
[[ "$TITLE" =~ $pattern ]]
|
|
22
|
+
check:
|
|
23
|
+
name: Python ${{ matrix.python }} on ${{ matrix.os }}
|
|
24
|
+
runs-on: ${{ matrix.os }}
|
|
25
|
+
strategy:
|
|
26
|
+
matrix:
|
|
27
|
+
os: [ubuntu-latest, windows-latest]
|
|
28
|
+
python: ['3.13', '3.14']
|
|
29
|
+
steps:
|
|
30
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
31
|
+
with:
|
|
32
|
+
persist-credentials: false
|
|
33
|
+
- uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
|
|
34
|
+
with:
|
|
35
|
+
python-version: ${{ matrix.python }}
|
|
36
|
+
enable-cache: false
|
|
37
|
+
- run: uv sync --locked
|
|
38
|
+
- run: uv run poe check
|
|
39
|
+
- run: uv build
|
|
40
|
+
- run: uv run twine check --strict dist/*
|
|
41
|
+
passed:
|
|
42
|
+
name: CI passed
|
|
43
|
+
if: always()
|
|
44
|
+
needs: [check, title]
|
|
45
|
+
runs-on: ubuntu-latest
|
|
46
|
+
steps:
|
|
47
|
+
- name: Require all checks
|
|
48
|
+
env:
|
|
49
|
+
RESULT: ${{ needs.check.result }}
|
|
50
|
+
TITLE_RESULT: ${{ needs.title.result }}
|
|
51
|
+
run: |
|
|
52
|
+
test "$RESULT" = success
|
|
53
|
+
test "$TITLE_RESULT" = success || test "$TITLE_RESULT" = skipped
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
name: Mutation alerts
|
|
2
|
+
on:
|
|
3
|
+
workflow_run: # zizmor: ignore[dangerous-triggers] -- only same-repo main push/schedule/manual evidence; fixed-main checkout; artifacts parsed as data, never executed
|
|
4
|
+
workflows: [Mutation]
|
|
5
|
+
types: [completed]
|
|
6
|
+
branches: [main]
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
inputs:
|
|
9
|
+
selftest:
|
|
10
|
+
description: Verify issue creation, update, deduplication, and recovery using an isolated test incident
|
|
11
|
+
type: boolean
|
|
12
|
+
required: true
|
|
13
|
+
default: true
|
|
14
|
+
permissions:
|
|
15
|
+
contents: read
|
|
16
|
+
concurrency:
|
|
17
|
+
group: mutation-alerts
|
|
18
|
+
cancel-in-progress: false
|
|
19
|
+
jobs:
|
|
20
|
+
validate-ref:
|
|
21
|
+
runs-on: ubuntu-latest
|
|
22
|
+
steps:
|
|
23
|
+
- name: Reject non-default manual refs
|
|
24
|
+
run: test "$GITHUB_REF" = refs/heads/main
|
|
25
|
+
reconcile:
|
|
26
|
+
needs: validate-ref
|
|
27
|
+
# Only trusted main results; never a pull_request or fork write context.
|
|
28
|
+
if: >-
|
|
29
|
+
github.ref == 'refs/heads/main' &&
|
|
30
|
+
(github.event_name == 'workflow_dispatch' ||
|
|
31
|
+
(github.event.workflow_run.head_repository.full_name == github.repository &&
|
|
32
|
+
github.event.workflow_run.head_branch == 'main' &&
|
|
33
|
+
contains(fromJSON('["push","schedule","workflow_dispatch"]'), github.event.workflow_run.event)))
|
|
34
|
+
runs-on: ubuntu-latest
|
|
35
|
+
timeout-minutes: 10
|
|
36
|
+
permissions:
|
|
37
|
+
contents: read
|
|
38
|
+
actions: read
|
|
39
|
+
issues: write
|
|
40
|
+
steps:
|
|
41
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
42
|
+
with:
|
|
43
|
+
persist-credentials: false
|
|
44
|
+
ref: main
|
|
45
|
+
- uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
|
|
46
|
+
with:
|
|
47
|
+
python-version: '3.13'
|
|
48
|
+
enable-cache: false
|
|
49
|
+
- name: Download evidence from the trusted main run
|
|
50
|
+
if: github.event_name == 'workflow_run'
|
|
51
|
+
continue-on-error: true
|
|
52
|
+
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
|
|
53
|
+
with:
|
|
54
|
+
name: mutation-report
|
|
55
|
+
path: mutation-report/
|
|
56
|
+
run-id: ${{ github.event.workflow_run.id }}
|
|
57
|
+
github-token: ${{ github.token }}
|
|
58
|
+
- name: Reconcile durable production alerts
|
|
59
|
+
if: github.event_name == 'workflow_run'
|
|
60
|
+
env:
|
|
61
|
+
GH_TOKEN: ${{ github.token }}
|
|
62
|
+
MUTATION_SHA: ${{ github.event.workflow_run.head_sha }}
|
|
63
|
+
MUTATION_RUN_URL: ${{ github.event.workflow_run.html_url }}
|
|
64
|
+
MUTATION_CONCLUSION: ${{ github.event.workflow_run.conclusion }}
|
|
65
|
+
MUTATION_RUN_ATTEMPT: ${{ github.event.workflow_run.run_attempt }}
|
|
66
|
+
run: uv run --no-project python scripts/mutation_alerts.py
|
|
67
|
+
- name: Verify hosted alert lifecycle
|
|
68
|
+
if: github.event_name == 'workflow_dispatch' && inputs.selftest
|
|
69
|
+
env:
|
|
70
|
+
GH_TOKEN: ${{ github.token }}
|
|
71
|
+
MUTATION_SHA: ${{ github.sha }}
|
|
72
|
+
MUTATION_RUN_URL: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
|
73
|
+
run: uv run --no-project python scripts/mutation_alerts.py --selftest
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
name: Mutation
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
branches: [main]
|
|
5
|
+
schedule:
|
|
6
|
+
- cron: '23 6 * * 1'
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
concurrency:
|
|
11
|
+
group: mutation-main
|
|
12
|
+
cancel-in-progress: false
|
|
13
|
+
jobs:
|
|
14
|
+
validate-ref:
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
steps:
|
|
17
|
+
- name: Reject non-default manual refs
|
|
18
|
+
run: test "$GITHUB_REF" = refs/heads/main
|
|
19
|
+
scan:
|
|
20
|
+
needs: validate-ref
|
|
21
|
+
if: github.ref == 'refs/heads/main'
|
|
22
|
+
runs-on: ubuntu-latest
|
|
23
|
+
timeout-minutes: 25
|
|
24
|
+
steps:
|
|
25
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
26
|
+
with:
|
|
27
|
+
persist-credentials: false
|
|
28
|
+
- uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
|
|
29
|
+
with:
|
|
30
|
+
python-version: '3.13'
|
|
31
|
+
enable-cache: false
|
|
32
|
+
- run: uv sync --locked --group mutation
|
|
33
|
+
- name: Run bounded asynchronous mutation analysis
|
|
34
|
+
run: |
|
|
35
|
+
mkdir -p mutation-report
|
|
36
|
+
set +e
|
|
37
|
+
timeout --signal=TERM --kill-after=10s 18m uv run --group mutation mutmut run --max-children 2 > mutation-report/run.log 2>&1
|
|
38
|
+
code=$?
|
|
39
|
+
uv run --group mutation mutmut export-cicd-stats >> mutation-report/run.log 2>&1
|
|
40
|
+
uv run --group mutation mutmut results --all true > mutation-report/results.txt 2>&1
|
|
41
|
+
results_code=$?
|
|
42
|
+
tar -czf mutation-report/mutants.tar.gz -C mutants/src codapact
|
|
43
|
+
archive_code=$?
|
|
44
|
+
if test "$code" -eq 0 && { test "$results_code" -ne 0 || test "$archive_code" -ne 0; }; then
|
|
45
|
+
code=1
|
|
46
|
+
fi
|
|
47
|
+
uv run python scripts/mutation_report.py --exit-code "$code" --stats mutants/mutmut-cicd-stats.json --output mutation-report/report.json
|
|
48
|
+
- name: Preserve evidence on failure or incomplete run
|
|
49
|
+
if: always()
|
|
50
|
+
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
|
51
|
+
with:
|
|
52
|
+
name: mutation-report
|
|
53
|
+
path: mutation-report/
|
|
54
|
+
if-no-files-found: warn
|
|
55
|
+
retention-days: 30
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
branches: [main]
|
|
5
|
+
workflow_dispatch:
|
|
6
|
+
permissions:
|
|
7
|
+
contents: read
|
|
8
|
+
concurrency:
|
|
9
|
+
group: release
|
|
10
|
+
cancel-in-progress: false
|
|
11
|
+
jobs:
|
|
12
|
+
version:
|
|
13
|
+
# Repository and publisher setup must be completed before enabling releases.
|
|
14
|
+
if: vars.RELEASES_ENABLED == 'true'
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
permissions:
|
|
17
|
+
contents: write
|
|
18
|
+
actions: write
|
|
19
|
+
pull-requests: write
|
|
20
|
+
issues: write
|
|
21
|
+
outputs:
|
|
22
|
+
created: ${{ steps.release.outputs.release_created }}
|
|
23
|
+
tag: ${{ steps.release.outputs.tag_name }}
|
|
24
|
+
steps:
|
|
25
|
+
- id: release
|
|
26
|
+
uses: googleapis/release-please-action@45996ed1f6d02564a971a2fa1b5860e934307cf7 # v5.0.0
|
|
27
|
+
with:
|
|
28
|
+
token: ${{ secrets.RELEASE_PLEASE_TOKEN || secrets.GITHUB_TOKEN }}
|
|
29
|
+
config-file: release-please-config.json
|
|
30
|
+
manifest-file: .release-please-manifest.json
|
|
31
|
+
- name: Start CI for release pull request
|
|
32
|
+
if: steps.release.outputs.prs_created == 'true'
|
|
33
|
+
env:
|
|
34
|
+
GH_TOKEN: ${{ github.token }}
|
|
35
|
+
PR_JSON: ${{ steps.release.outputs.pr }}
|
|
36
|
+
run: |
|
|
37
|
+
branch=$(jq -r '.headBranchName' <<< "$PR_JSON")
|
|
38
|
+
gh workflow run ci.yml --repo "$GITHUB_REPOSITORY" --ref "$branch"
|
|
39
|
+
ci:
|
|
40
|
+
needs: version
|
|
41
|
+
if: needs.version.outputs.created == 'true'
|
|
42
|
+
uses: ./.github/workflows/ci.yml # zizmor: ignore[self-repository] -- portable local reuse, matching VerdiClip
|
|
43
|
+
permissions:
|
|
44
|
+
contents: read
|
|
45
|
+
build:
|
|
46
|
+
needs: [version, ci]
|
|
47
|
+
runs-on: ubuntu-latest
|
|
48
|
+
steps:
|
|
49
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
50
|
+
with:
|
|
51
|
+
persist-credentials: false
|
|
52
|
+
ref: ${{ needs.version.outputs.tag }}
|
|
53
|
+
- uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
|
|
54
|
+
with:
|
|
55
|
+
enable-cache: false
|
|
56
|
+
- run: uv sync --locked
|
|
57
|
+
- run: uv build
|
|
58
|
+
- run: uv run twine check --strict dist/*
|
|
59
|
+
- name: Verify distribution and tag versions
|
|
60
|
+
env:
|
|
61
|
+
RELEASE_TAG: ${{ needs.version.outputs.tag }}
|
|
62
|
+
run: uv run python scripts/verify_dist.py
|
|
63
|
+
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
|
64
|
+
with:
|
|
65
|
+
name: dist
|
|
66
|
+
path: dist/
|
|
67
|
+
publish:
|
|
68
|
+
needs: [version, build]
|
|
69
|
+
runs-on: ubuntu-latest
|
|
70
|
+
environment: pypi
|
|
71
|
+
permissions:
|
|
72
|
+
id-token: write
|
|
73
|
+
attestations: write
|
|
74
|
+
contents: write
|
|
75
|
+
steps:
|
|
76
|
+
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
|
|
77
|
+
with:
|
|
78
|
+
name: dist
|
|
79
|
+
path: dist/
|
|
80
|
+
- uses: actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4.2.2
|
|
81
|
+
with:
|
|
82
|
+
subject-path: dist/*
|
|
83
|
+
- uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
|
|
84
|
+
- name: Attach distributions
|
|
85
|
+
env:
|
|
86
|
+
GH_TOKEN: ${{ github.token }}
|
|
87
|
+
TAG: ${{ needs.version.outputs.tag }}
|
|
88
|
+
run: gh release upload "$TAG" dist/* --repo "$GITHUB_REPOSITORY"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{".":"0.1.0"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0 (2026-10-29)
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
* add generation manifests and XDG runtime profiles ([cd0e6a2](https://github.com/mikejhill/codapact/commit/cd0e6a20e813423d3b33ca5ba277a036c482dd8c))
|
|
8
|
+
* initialize codapact ([7daa7e2](https://github.com/mikejhill/codapact/commit/7daa7e2534bdd59bcd555dc90ec2e97a002f130c))
|
|
9
|
+
|
|
10
|
+
### Bug Fixes
|
|
11
|
+
|
|
12
|
+
* document generated commands and release handoff ([9ea472c](https://github.com/mikejhill/codapact/commit/9ea472ca5e3cfe9fdf4bbc94bb22511d87eece22))
|
|
13
|
+
* harden contracts and add mutation alerts ([b4b1a06](https://github.com/mikejhill/codapact/commit/b4b1a06d2029a53fa68783f6ecd1c0dedb7854e2))
|
|
14
|
+
* reconcile asynchronous mutation alerts ([ba1737d](https://github.com/mikejhill/codapact/commit/ba1737d33f9e6157a7d9fe6f6c8b1d2878917dec))
|
codapact-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Mike Hill
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
codapact-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: codapact
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Contracts into callable tools: pluggable API client and CLI generation.
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Requires-Dist: pyyaml>=6.0.3,<7
|
|
8
|
+
Requires-Dist: jsonschema>=4.25.1,<5
|
|
9
|
+
Requires-Python: >=3.13
|
|
10
|
+
Project-URL: Homepage, https://github.com/mikejhill/codapact
|
|
11
|
+
Project-URL: Documentation, https://github.com/mikejhill/codapact#readme
|
|
12
|
+
Project-URL: Changelog, https://github.com/mikejhill/codapact/blob/main/CHANGELOG.md
|
|
13
|
+
Project-URL: Issues, https://github.com/mikejhill/codapact/issues
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
|
|
16
|
+
# CodaPact
|
|
17
|
+
|
|
18
|
+

|
|
19
|
+
|
|
20
|
+
**Contracts into callable tools.**
|
|
21
|
+
|
|
22
|
+
This first iteration generates an installable, typed Python client and a
|
|
23
|
+
scriptable CLI from a local or remote OpenAPI contract. The package, module, and
|
|
24
|
+
generator CLI are named `codapact`. Install a published release with
|
|
25
|
+
`uv tool install codapact`, or use the source workflow below.
|
|
26
|
+
|
|
27
|
+
```powershell
|
|
28
|
+
uv sync
|
|
29
|
+
uv run codapact generate examples/pets.yaml --output .tmp/pets-client --package pets_client
|
|
30
|
+
uv build
|
|
31
|
+
uv pip install --no-deps .tmp/pets-client
|
|
32
|
+
uv run pets-client --config examples/runtime.json get-pet --arg-pet-id 7
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
The example server address is intentionally inert. Override `base_url` with your
|
|
36
|
+
own trusted endpoint and set the environment variable referenced by the runtime
|
|
37
|
+
configuration. Tests use isolated loopback HTTP servers and synthetic credentials.
|
|
38
|
+
|
|
39
|
+
```python
|
|
40
|
+
from pets_client import Client
|
|
41
|
+
|
|
42
|
+
client = Client(settings={"auth": {"token": {"env": "PETS_TOKEN"}}})
|
|
43
|
+
pet = client.get_pet(parameters={"pet_id": 7})
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Reusable generation values are supported with `uv run codapact generate
|
|
47
|
+
--manifest examples/pets.codapact.yaml`. The resulting `pets` command discovers
|
|
48
|
+
`config.json` and `auth.json` in `$XDG_CONFIG_HOME/pets` or `~/.config/pets`.
|
|
49
|
+
Override its directory with `pets --config-dir PATH ...`. See the configuration
|
|
50
|
+
guide for precedence, credential-file permissions, and every generation override.
|
|
51
|
+
|
|
52
|
+
- [Architecture and extension contracts](docs/architecture.md)
|
|
53
|
+
- [Supported features and safety boundaries](docs/support.md)
|
|
54
|
+
- [CLI definition and runtime configuration](docs/configuration.md)
|
|
55
|
+
- [Release process](docs/releasing.md)
|
|
56
|
+
- [Verification evidence and limits](docs/verification.md)
|
|
57
|
+
- [Asynchronous mutation testing and open alerts](docs/mutation.md)
|
|
58
|
+
|
|
59
|
+
Run `uv run poe check` for formatting, lint, type checking, and tests. Generated
|
|
60
|
+
packages depend on this runtime at the exact generator version. For unreleased
|
|
61
|
+
source changes, install the local runtime wheel and generated wheel together.
|
|
62
|
+
The end-to-end test proves that workflow in a fresh environment.
|
codapact-0.1.0/README.md
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# CodaPact
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
|
|
5
|
+
**Contracts into callable tools.**
|
|
6
|
+
|
|
7
|
+
This first iteration generates an installable, typed Python client and a
|
|
8
|
+
scriptable CLI from a local or remote OpenAPI contract. The package, module, and
|
|
9
|
+
generator CLI are named `codapact`. Install a published release with
|
|
10
|
+
`uv tool install codapact`, or use the source workflow below.
|
|
11
|
+
|
|
12
|
+
```powershell
|
|
13
|
+
uv sync
|
|
14
|
+
uv run codapact generate examples/pets.yaml --output .tmp/pets-client --package pets_client
|
|
15
|
+
uv build
|
|
16
|
+
uv pip install --no-deps .tmp/pets-client
|
|
17
|
+
uv run pets-client --config examples/runtime.json get-pet --arg-pet-id 7
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
The example server address is intentionally inert. Override `base_url` with your
|
|
21
|
+
own trusted endpoint and set the environment variable referenced by the runtime
|
|
22
|
+
configuration. Tests use isolated loopback HTTP servers and synthetic credentials.
|
|
23
|
+
|
|
24
|
+
```python
|
|
25
|
+
from pets_client import Client
|
|
26
|
+
|
|
27
|
+
client = Client(settings={"auth": {"token": {"env": "PETS_TOKEN"}}})
|
|
28
|
+
pet = client.get_pet(parameters={"pet_id": 7})
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Reusable generation values are supported with `uv run codapact generate
|
|
32
|
+
--manifest examples/pets.codapact.yaml`. The resulting `pets` command discovers
|
|
33
|
+
`config.json` and `auth.json` in `$XDG_CONFIG_HOME/pets` or `~/.config/pets`.
|
|
34
|
+
Override its directory with `pets --config-dir PATH ...`. See the configuration
|
|
35
|
+
guide for precedence, credential-file permissions, and every generation override.
|
|
36
|
+
|
|
37
|
+
- [Architecture and extension contracts](docs/architecture.md)
|
|
38
|
+
- [Supported features and safety boundaries](docs/support.md)
|
|
39
|
+
- [CLI definition and runtime configuration](docs/configuration.md)
|
|
40
|
+
- [Release process](docs/releasing.md)
|
|
41
|
+
- [Verification evidence and limits](docs/verification.md)
|
|
42
|
+
- [Asynchronous mutation testing and open alerts](docs/mutation.md)
|
|
43
|
+
|
|
44
|
+
Run `uv run poe check` for formatting, lint, type checking, and tests. Generated
|
|
45
|
+
packages depend on this runtime at the exact generator version. For unreleased
|
|
46
|
+
source changes, install the local runtime wheel and generated wheel together.
|
|
47
|
+
The end-to-end test proves that workflow in a fresh environment.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128" role="img" aria-labelledby="title desc">
|
|
2
|
+
<title id="title">CodaPact</title>
|
|
3
|
+
<desc id="desc">A coda-inspired open ring with a shared vertical axis and two balanced horizontal strokes.</desc>
|
|
4
|
+
<path d="M50 29a37 37 0 0 0 0 70M78 29a37 37 0 0 1 0 70" fill="none" stroke="#15a99b" stroke-width="12" stroke-linecap="round"/>
|
|
5
|
+
<path d="M64 12v104" fill="none" stroke="#18283e" stroke-width="10" stroke-linecap="round"/>
|
|
6
|
+
<path d="M13 64h38m26 0h38" fill="none" stroke="#18283e" stroke-width="10" stroke-linecap="round"/>
|
|
7
|
+
<circle cx="64" cy="64" r="7" fill="#d99732"/>
|
|
8
|
+
</svg>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="500" height="166" viewBox="0 0 500 166" role="img" aria-labelledby="title desc">
|
|
2
|
+
<title id="title">CodaPact — Contracts into callable tools</title>
|
|
3
|
+
<desc id="desc">A teal coda mark and navy wordmark, with an amber central accent.</desc>
|
|
4
|
+
<g transform="translate(10 19)">
|
|
5
|
+
<path d="M50 29a37 37 0 0 0 0 70M78 29a37 37 0 0 1 0 70" fill="none" stroke="#15a99b" stroke-width="12" stroke-linecap="round"/>
|
|
6
|
+
<path d="M64 12v104M13 64h38m26 0h38" fill="none" stroke="#18283e" stroke-width="10" stroke-linecap="round"/>
|
|
7
|
+
<circle cx="64" cy="64" r="7" fill="#d99732"/>
|
|
8
|
+
</g>
|
|
9
|
+
<text x="166" y="88" fill="#18283e" font-family="Segoe UI,Inter,Arial,sans-serif" font-size="67" font-weight="650" letter-spacing="-2">CodaPact</text>
|
|
10
|
+
<text x="170" y="125" fill="#52627a" font-family="Segoe UI,Inter,Arial,sans-serif" font-size="22">Contracts into callable tools.</text>
|
|
11
|
+
</svg>
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Architecture
|
|
2
|
+
|
|
3
|
+
Python 3.13 is the initial implementation and generated language. It fits the
|
|
4
|
+
existing uv-based release process and supports typed dictionaries without a
|
|
5
|
+
large code generation framework. Runtime schemas validate data independently
|
|
6
|
+
of static annotations. TypeScript remains a future target.
|
|
7
|
+
|
|
8
|
+
```mermaid
|
|
9
|
+
flowchart LR
|
|
10
|
+
A[Bounded JSON/YAML loader] --> B[Contract translator plugin]
|
|
11
|
+
B --> C[Version 1 shared IR]
|
|
12
|
+
C --> D[Python generator plugin]
|
|
13
|
+
C --> E[CLI generator plugin]
|
|
14
|
+
D --> F[Ownership manifest]
|
|
15
|
+
E --> F
|
|
16
|
+
F --> G[Generated client and CLI]
|
|
17
|
+
G --> H[Authorization policy]
|
|
18
|
+
H --> I[Authentication provider]
|
|
19
|
+
I --> J[Transport]
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Layer contracts
|
|
23
|
+
|
|
24
|
+
| Layer | Initial implementation | Extension boundary |
|
|
25
|
+
| --- | --- | --- |
|
|
26
|
+
| Loading | Bounded JSON/YAML; local files and HTTP(S) | Explicit transport injection |
|
|
27
|
+
| Translation | OpenAPI 3.0 JSON HTTP subset | `Translator.translate(document) -> Contract` |
|
|
28
|
+
| Shared model | Frozen contract and operation records; schema dictionaries | IR major version, metadata, capability identifiers |
|
|
29
|
+
| Library generation | Typed dictionaries, typed methods, JSON IR resource | `Generator.generate(contract, package) -> files` |
|
|
30
|
+
| CLI generation | Version 1 definition, argparse commands | Independent generator and CLI runtime |
|
|
31
|
+
| Execution | Schema validation and JSON serialization | Generated client inherits `ClientBase` |
|
|
32
|
+
| Authentication | Environment-backed bearer, basic, header API key | `AuthProvider.headers(name, scheme)` |
|
|
33
|
+
| Policy | Operation allow/deny lists | `AuthorizationPolicy.authorize(operation)` |
|
|
34
|
+
| Transport | Pinned DNS, bounded HTTP, verified TLS | `Transport.send(...) -> Response` |
|
|
35
|
+
| Orchestration | Explicit registry, capability negotiation, ownership checks | Registry supplied to `generate` |
|
|
36
|
+
|
|
37
|
+
Plugin API version 1 and IR version 1 are separate contracts. Registration rejects
|
|
38
|
+
duplicate names and incompatible API versions. Targets declare required
|
|
39
|
+
capabilities; translators declare capabilities they can produce. Plugins are
|
|
40
|
+
trusted Python objects registered by the host application, never imported from
|
|
41
|
+
contract or configuration strings. A fixture translator and operation-index
|
|
42
|
+
generator exercise a complete alternate plugin path in tests.
|
|
43
|
+
|
|
44
|
+
The normalized IR records operations, parameter schemas, JSON request bodies,
|
|
45
|
+
successful and error response schemas, named component types, security OR/AND
|
|
46
|
+
requirements, and extensible metadata. OAuth2, GraphQL, Turbo-Stream, gRPC,
|
|
47
|
+
streaming transports, other languages, and other CLI styles are future plugins.
|
|
48
|
+
They are not implemented or advertised as supported.
|
|
49
|
+
|
|
50
|
+
## Custom runtime hooks
|
|
51
|
+
|
|
52
|
+
Pass `auth=`, `policy=`, and `transport=` objects to a generated `Client`. Hooks
|
|
53
|
+
are explicit application code. An auth provider returns headers or raises
|
|
54
|
+
`AuthError` when credentials are unavailable. A policy raises `PolicyError`
|
|
55
|
+
before credentials are resolved and before network activity. Transport plugins
|
|
56
|
+
must preserve redirect, credential, timeout, and response-size guarantees.
|
|
57
|
+
|
|
58
|
+
The generated CLI uses the declarative built-in hooks. Applications needing
|
|
59
|
+
custom hooks can call `run_cli` with their own client factory. No configuration
|
|
60
|
+
option dynamically imports code or executes shell commands.
|
|
61
|
+
|
|
62
|
+
## Regeneration
|
|
63
|
+
|
|
64
|
+
Generators return relative paths and Unicode file contents. The writer checks
|
|
65
|
+
all planned writes and removals before mutation, verifies SHA-256 ownership,
|
|
66
|
+
refuses modified/unowned files, rejects traversal and symlinks/junctions, and
|
|
67
|
+
preserves unrelated files. Obsolete owned files are removed. The manifest is
|
|
68
|
+
deterministic and written last; each file replacement is atomic.
|
|
69
|
+
|
|
70
|
+
A multi-file update is not an atomic filesystem transaction. If interrupted,
|
|
71
|
+
the next run fails closed on mismatched ownership. Preserve edited files and
|
|
72
|
+
generate into a new directory to recover. Concurrent generation into the same
|
|
73
|
+
directory is unsupported. Local plugins and users able to race filesystem
|
|
74
|
+
mutations are trusted; this is not an operating-system sandbox.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# CodaPact identity
|
|
2
|
+
|
|
3
|
+
**CodaPact** joins a musical coda, code, a contract, and the idea of impact.
|
|
4
|
+
The tagline is **Contracts into callable tools.**
|
|
5
|
+
|
|
6
|
+
The original mark takes the coda's circle and axes and opens the ring into two
|
|
7
|
+
balanced boundaries. It suggests a shared contract between interchangeable
|
|
8
|
+
implementations. The amber center marks the point where a definition becomes
|
|
9
|
+
an executable call. The identity uses a single symbol, without a collage of
|
|
10
|
+
music notes, terminal windows, and paperwork.
|
|
11
|
+
|
|
12
|
+
| Role | Color |
|
|
13
|
+
| --- | --- |
|
|
14
|
+
| Wordmark and axes | Navy `#18283e` |
|
|
15
|
+
| Open ring | Teal `#15a99b` |
|
|
16
|
+
| Execution point | Amber `#d99732` |
|
|
17
|
+
| Supporting text | Slate `#52627a` |
|
|
18
|
+
|
|
19
|
+
Use [the wordmark](../branding/wordmark.svg) on light backgrounds and
|
|
20
|
+
[the standalone mark](../branding/mark.svg) where space is limited. SVGs use
|
|
21
|
+
system fonts and contain no scripts, external resources, or embedded images.
|
|
22
|
+
|
|
23
|
+
Mike selected the name on 2026-10-29. Preliminary exact-name repository and
|
|
24
|
+
registry searches found no obvious collisions. This is not a reservation or
|
|
25
|
+
legal clearance; recheck before publication.
|