shotgate 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.
- shotgate-0.1.0/.containerignore +23 -0
- shotgate-0.1.0/.github/ISSUE_TEMPLATE/bug_report.yml +44 -0
- shotgate-0.1.0/.github/ISSUE_TEMPLATE/feature_request.yml +34 -0
- shotgate-0.1.0/.github/PULL_REQUEST_TEMPLATE.md +24 -0
- shotgate-0.1.0/.github/dependabot.yml +19 -0
- shotgate-0.1.0/.github/workflows/ci.yml +134 -0
- shotgate-0.1.0/.github/workflows/release.yml +129 -0
- shotgate-0.1.0/.gitignore +48 -0
- shotgate-0.1.0/.gitlab-ci.yml +57 -0
- shotgate-0.1.0/CHANGELOG.md +103 -0
- shotgate-0.1.0/CODEOWNERS +9 -0
- shotgate-0.1.0/CODE_OF_CONDUCT.md +37 -0
- shotgate-0.1.0/CONTRIBUTING.md +82 -0
- shotgate-0.1.0/Containerfile +73 -0
- shotgate-0.1.0/GOVERNANCE.md +48 -0
- shotgate-0.1.0/Jenkinsfile +60 -0
- shotgate-0.1.0/LICENSE +202 -0
- shotgate-0.1.0/MAINTAINERS.md +42 -0
- shotgate-0.1.0/Makefile +105 -0
- shotgate-0.1.0/NOTICE +7 -0
- shotgate-0.1.0/PKG-INFO +326 -0
- shotgate-0.1.0/README.md +279 -0
- shotgate-0.1.0/SECURITY.md +33 -0
- shotgate-0.1.0/docs/README.md +18 -0
- shotgate-0.1.0/docs/adr/0001-record-architecture-decisions.md +24 -0
- shotgate-0.1.0/docs/adr/0002-statistical-validation-core.md +38 -0
- shotgate-0.1.0/docs/adr/0003-container-and-vm-isolation.md +44 -0
- shotgate-0.1.0/docs/architecture.md +150 -0
- shotgate-0.1.0/docs/assertions.md +137 -0
- shotgate-0.1.0/docs/assets/bell-state-demo.svg +63 -0
- shotgate-0.1.0/docs/diagrams/architecture.mmd +26 -0
- shotgate-0.1.0/docs/diagrams/pipeline.mmd +12 -0
- shotgate-0.1.0/docs/getting-started.md +126 -0
- shotgate-0.1.0/docs/hardware-validation.md +133 -0
- shotgate-0.1.0/docs/motivation.md +76 -0
- shotgate-0.1.0/docs/pipeline.md +145 -0
- shotgate-0.1.0/docs/workflow-spec.md +87 -0
- shotgate-0.1.0/examples/bell-state/bell.qasm +8 -0
- shotgate-0.1.0/examples/bell-state/workflow.yaml +43 -0
- shotgate-0.1.0/examples/bell-state-hardware/bell.qasm +8 -0
- shotgate-0.1.0/examples/bell-state-hardware/workflow.yaml +40 -0
- shotgate-0.1.0/examples/ghz-state/ghz.qasm +9 -0
- shotgate-0.1.0/examples/ghz-state/workflow.yaml +31 -0
- shotgate-0.1.0/examples/grover-2q/grover.qasm +22 -0
- shotgate-0.1.0/examples/grover-2q/workflow.yaml +30 -0
- shotgate-0.1.0/infra/qemu/README.md +49 -0
- shotgate-0.1.0/infra/qemu/cloud-init/meta-data +2 -0
- shotgate-0.1.0/infra/qemu/cloud-init/user-data +43 -0
- shotgate-0.1.0/infra/qemu/create-runner-vm.sh +133 -0
- shotgate-0.1.0/infra/terraform/README.md +64 -0
- shotgate-0.1.0/infra/terraform/examples/basic/main.tf +22 -0
- shotgate-0.1.0/infra/terraform/main.tf +61 -0
- shotgate-0.1.0/infra/terraform/outputs.tf +19 -0
- shotgate-0.1.0/infra/terraform/variables.tf +58 -0
- shotgate-0.1.0/infra/terraform/versions.tf +4 -0
- shotgate-0.1.0/pyproject.toml +101 -0
- shotgate-0.1.0/scripts/demo.sh +41 -0
- shotgate-0.1.0/src/shotgate/__init__.py +24 -0
- shotgate-0.1.0/src/shotgate/__main__.py +8 -0
- shotgate-0.1.0/src/shotgate/backends/__init__.py +19 -0
- shotgate-0.1.0/src/shotgate/backends/base.py +53 -0
- shotgate-0.1.0/src/shotgate/backends/ibm_runtime.py +153 -0
- shotgate-0.1.0/src/shotgate/backends/local_aer.py +46 -0
- shotgate-0.1.0/src/shotgate/backends/registry.py +89 -0
- shotgate-0.1.0/src/shotgate/circuits/__init__.py +7 -0
- shotgate-0.1.0/src/shotgate/circuits/loader.py +57 -0
- shotgate-0.1.0/src/shotgate/cli.py +130 -0
- shotgate-0.1.0/src/shotgate/config.py +178 -0
- shotgate-0.1.0/src/shotgate/pytest_plugin.py +195 -0
- shotgate-0.1.0/src/shotgate/report.py +183 -0
- shotgate-0.1.0/src/shotgate/runner.py +153 -0
- shotgate-0.1.0/src/shotgate/telemetry.py +40 -0
- shotgate-0.1.0/src/shotgate/validation/__init__.py +11 -0
- shotgate-0.1.0/src/shotgate/validation/assertions.py +240 -0
- shotgate-0.1.0/src/shotgate/validation/metrics.py +247 -0
- shotgate-0.1.0/tests/conftest.py +7 -0
- shotgate-0.1.0/tests/test_assertions.py +108 -0
- shotgate-0.1.0/tests/test_config.py +116 -0
- shotgate-0.1.0/tests/test_ibm_backend.py +144 -0
- shotgate-0.1.0/tests/test_metrics.py +101 -0
- shotgate-0.1.0/tests/test_pytest_plugin.py +177 -0
- shotgate-0.1.0/tests/test_report.py +71 -0
- shotgate-0.1.0/tests/test_runner_integration.py +72 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Keep the build context small and reproducible.
|
|
2
|
+
.git
|
|
3
|
+
.github
|
|
4
|
+
.venv
|
|
5
|
+
venv
|
|
6
|
+
**/__pycache__
|
|
7
|
+
**/*.pyc
|
|
8
|
+
.pytest_cache
|
|
9
|
+
.ruff_cache
|
|
10
|
+
.mypy_cache
|
|
11
|
+
htmlcov
|
|
12
|
+
*.egg-info
|
|
13
|
+
dist
|
|
14
|
+
build
|
|
15
|
+
docs
|
|
16
|
+
infra
|
|
17
|
+
report-quantum-devops.md
|
|
18
|
+
*.xml
|
|
19
|
+
*.json
|
|
20
|
+
!examples/**/*.json
|
|
21
|
+
.gitignore
|
|
22
|
+
.containerignore
|
|
23
|
+
.dockerignore
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
name: Bug report
|
|
2
|
+
description: Report incorrect behavior in shotgate
|
|
3
|
+
labels: ["bug"]
|
|
4
|
+
body:
|
|
5
|
+
- type: markdown
|
|
6
|
+
attributes:
|
|
7
|
+
value: Thanks for filing a bug! Please include enough detail to reproduce it.
|
|
8
|
+
- type: textarea
|
|
9
|
+
id: what-happened
|
|
10
|
+
attributes:
|
|
11
|
+
label: What happened?
|
|
12
|
+
description: A clear description of the bug and what you expected instead.
|
|
13
|
+
validations:
|
|
14
|
+
required: true
|
|
15
|
+
- type: textarea
|
|
16
|
+
id: workflow
|
|
17
|
+
attributes:
|
|
18
|
+
label: Workflow YAML
|
|
19
|
+
description: The (minimal) workflow that reproduces the issue.
|
|
20
|
+
render: yaml
|
|
21
|
+
- type: textarea
|
|
22
|
+
id: command
|
|
23
|
+
attributes:
|
|
24
|
+
label: Command and output
|
|
25
|
+
description: How you ran shotgate (e.g. `make run WORKFLOW=...`) and the output.
|
|
26
|
+
render: shell
|
|
27
|
+
- type: input
|
|
28
|
+
id: version
|
|
29
|
+
attributes:
|
|
30
|
+
label: shotgate version / image tag
|
|
31
|
+
validations:
|
|
32
|
+
required: true
|
|
33
|
+
- type: dropdown
|
|
34
|
+
id: backend
|
|
35
|
+
attributes:
|
|
36
|
+
label: Backend
|
|
37
|
+
options: [local-aer, ibm, braket, other]
|
|
38
|
+
validations:
|
|
39
|
+
required: true
|
|
40
|
+
- type: input
|
|
41
|
+
id: environment
|
|
42
|
+
attributes:
|
|
43
|
+
label: Environment
|
|
44
|
+
description: Podman/QEMU versions, host OS.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
name: Feature request
|
|
2
|
+
description: Suggest a new assertion oracle, backend, reporter, or capability
|
|
3
|
+
labels: ["enhancement"]
|
|
4
|
+
body:
|
|
5
|
+
- type: textarea
|
|
6
|
+
id: problem
|
|
7
|
+
attributes:
|
|
8
|
+
label: Problem
|
|
9
|
+
description: What can't you do today? What quantum-DevOps gap does this close?
|
|
10
|
+
validations:
|
|
11
|
+
required: true
|
|
12
|
+
- type: textarea
|
|
13
|
+
id: proposal
|
|
14
|
+
attributes:
|
|
15
|
+
label: Proposed solution
|
|
16
|
+
description: Sketch the YAML/CLI/API you'd want. Statistical rationale welcome.
|
|
17
|
+
validations:
|
|
18
|
+
required: true
|
|
19
|
+
- type: dropdown
|
|
20
|
+
id: area
|
|
21
|
+
attributes:
|
|
22
|
+
label: Area
|
|
23
|
+
options:
|
|
24
|
+
- Assertion oracle
|
|
25
|
+
- Backend (provider)
|
|
26
|
+
- Reporter / integration
|
|
27
|
+
- Infrastructure (Terraform / QEMU / Helm)
|
|
28
|
+
- Other
|
|
29
|
+
validations:
|
|
30
|
+
required: true
|
|
31
|
+
- type: textarea
|
|
32
|
+
id: alternatives
|
|
33
|
+
attributes:
|
|
34
|
+
label: Alternatives considered
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Summary
|
|
2
|
+
|
|
3
|
+
<!-- What does this PR change and why? Link any related issues. -->
|
|
4
|
+
|
|
5
|
+
## Type of change
|
|
6
|
+
|
|
7
|
+
- [ ] Bug fix
|
|
8
|
+
- [ ] New feature (new assertion oracle / backend / reporter)
|
|
9
|
+
- [ ] Documentation
|
|
10
|
+
- [ ] Infrastructure (Containerfile, CI, Terraform, QEMU)
|
|
11
|
+
|
|
12
|
+
## Checklist
|
|
13
|
+
|
|
14
|
+
- [ ] `make check` passes (ruff + full test suite in containers)
|
|
15
|
+
- [ ] New/changed behavior is covered by tests
|
|
16
|
+
- [ ] Docs updated (`docs/`, `README.md`) where relevant
|
|
17
|
+
- [ ] For a new assertion type: added to `ASSERTION_TYPES`, documented in
|
|
18
|
+
`docs/assertions.md`, and covered by a unit test
|
|
19
|
+
- [ ] For a new backend: registered in `backends/registry.py` and import-guarded
|
|
20
|
+
so the validation core stays SDK-free
|
|
21
|
+
|
|
22
|
+
## Notes for reviewers
|
|
23
|
+
|
|
24
|
+
<!-- Anything that needs special attention, trade-offs, or follow-ups. -->
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
updates:
|
|
3
|
+
- package-ecosystem: pip
|
|
4
|
+
directory: "/"
|
|
5
|
+
schedule:
|
|
6
|
+
interval: weekly
|
|
7
|
+
groups:
|
|
8
|
+
python-deps:
|
|
9
|
+
patterns: ["*"]
|
|
10
|
+
|
|
11
|
+
- package-ecosystem: github-actions
|
|
12
|
+
directory: "/"
|
|
13
|
+
schedule:
|
|
14
|
+
interval: weekly
|
|
15
|
+
|
|
16
|
+
- package-ecosystem: docker
|
|
17
|
+
directory: "/"
|
|
18
|
+
schedule:
|
|
19
|
+
interval: weekly
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
name: ci
|
|
2
|
+
|
|
3
|
+
# Container-native CI: every job runs tools inside Podman containers, mirroring
|
|
4
|
+
# exactly what a developer gets locally with `make`. No language toolchains are
|
|
5
|
+
# installed onto the runner directly.
|
|
6
|
+
#
|
|
7
|
+
# NOTE: This is shotgate's OWN repository CI, so it builds the image from source to
|
|
8
|
+
# test the code under change. CONSUMERS should instead *pull* the published image
|
|
9
|
+
# (`podman run ghcr.io/coldqubit/shotgate:latest run workflow.yaml`), as shown in
|
|
10
|
+
# README.md and the GitLab/Jenkins references in docs/pipeline.md.
|
|
11
|
+
|
|
12
|
+
on:
|
|
13
|
+
push:
|
|
14
|
+
branches: [main]
|
|
15
|
+
pull_request:
|
|
16
|
+
|
|
17
|
+
permissions:
|
|
18
|
+
contents: read
|
|
19
|
+
|
|
20
|
+
concurrency:
|
|
21
|
+
group: ci-${{ github.ref }}
|
|
22
|
+
cancel-in-progress: true
|
|
23
|
+
|
|
24
|
+
jobs:
|
|
25
|
+
lint-and-core-tests:
|
|
26
|
+
name: lint + core tests
|
|
27
|
+
runs-on: ubuntu-latest
|
|
28
|
+
steps:
|
|
29
|
+
- uses: actions/checkout@v4
|
|
30
|
+
|
|
31
|
+
- name: ruff + mypy + core unit tests (containerized)
|
|
32
|
+
run: |
|
|
33
|
+
podman run --rm -v "$PWD:/work:Z" -w /work \
|
|
34
|
+
docker.io/library/python:3.12-slim bash -euc "
|
|
35
|
+
pip install -q -e '.[dev]'
|
|
36
|
+
ruff check src tests
|
|
37
|
+
mypy
|
|
38
|
+
pytest -q -m 'not integration' --junitxml=core-junit.xml
|
|
39
|
+
"
|
|
40
|
+
|
|
41
|
+
- name: Upload core test report
|
|
42
|
+
if: always()
|
|
43
|
+
uses: actions/upload-artifact@v4
|
|
44
|
+
with:
|
|
45
|
+
name: core-junit
|
|
46
|
+
path: core-junit.xml
|
|
47
|
+
|
|
48
|
+
image-and-integration:
|
|
49
|
+
name: build image + integration + example gates
|
|
50
|
+
runs-on: ubuntu-latest
|
|
51
|
+
steps:
|
|
52
|
+
- uses: actions/checkout@v4
|
|
53
|
+
|
|
54
|
+
- name: Build shotgate runtime image
|
|
55
|
+
run: podman build -t shotgate:ci .
|
|
56
|
+
|
|
57
|
+
- name: Build test image and run full suite (unit + integration)
|
|
58
|
+
run: |
|
|
59
|
+
podman build --target test -t shotgate:ci-test .
|
|
60
|
+
podman run --rm -v "$PWD:/work:Z" shotgate:ci-test \
|
|
61
|
+
pytest -q --junitxml=/work/integration-junit.xml
|
|
62
|
+
|
|
63
|
+
- name: Run example workflows as quality gates
|
|
64
|
+
run: |
|
|
65
|
+
set -euo pipefail
|
|
66
|
+
# Map the runner user through the container userns so reports are writable.
|
|
67
|
+
USERMAP="--userns=keep-id --user $(id -u):$(id -g)"
|
|
68
|
+
for wf in bell-state ghz-state grover-2q; do
|
|
69
|
+
echo "::group::shotgate run examples/${wf}"
|
|
70
|
+
podman run --rm $USERMAP -v "$PWD:/work:Z" -w /work shotgate:ci \
|
|
71
|
+
run "examples/${wf}/workflow.yaml" \
|
|
72
|
+
--junit "report-${wf}.xml" --markdown "summary-${wf}.md"
|
|
73
|
+
cat "summary-${wf}.md" >> "$GITHUB_STEP_SUMMARY"
|
|
74
|
+
echo "::endgroup::"
|
|
75
|
+
done
|
|
76
|
+
|
|
77
|
+
- name: Upload reports
|
|
78
|
+
if: always()
|
|
79
|
+
uses: actions/upload-artifact@v4
|
|
80
|
+
with:
|
|
81
|
+
name: shotgate-reports
|
|
82
|
+
path: |
|
|
83
|
+
report-*.xml
|
|
84
|
+
integration-junit.xml
|
|
85
|
+
|
|
86
|
+
pip-consumer-path:
|
|
87
|
+
name: pip path (CLI + pytest plugin)
|
|
88
|
+
runs-on: ubuntu-latest
|
|
89
|
+
steps:
|
|
90
|
+
- uses: actions/checkout@v4
|
|
91
|
+
|
|
92
|
+
- name: pip install and exercise the CLI and pytest plugin (containerized)
|
|
93
|
+
run: |
|
|
94
|
+
podman run --rm -v "$PWD:/work:Z" -w /work \
|
|
95
|
+
docker.io/library/python:3.12-slim bash -euc "
|
|
96
|
+
pip install -q '.[aer,dev]'
|
|
97
|
+
# The pytest11 entry point must expose --shotgate after a pip install.
|
|
98
|
+
pytest --help 2>/dev/null | grep -q -- '--shotgate'
|
|
99
|
+
# CLI consumer path: gate a Bell workflow and emit a JUnit report.
|
|
100
|
+
shotgate run examples/bell-state/workflow.yaml --junit cli-junit.xml
|
|
101
|
+
# Plugin consumer path: in an isolated directory (free of this repo's
|
|
102
|
+
# pytest testpaths), each assertion of the workflow becomes one pytest
|
|
103
|
+
# item. pytest exits non-zero if nothing is collected or a gate fails.
|
|
104
|
+
cp -r examples/bell-state /tmp/gate
|
|
105
|
+
cd /tmp/gate
|
|
106
|
+
pytest -q --shotgate workflow.yaml --junitxml=/work/plugin-junit.xml
|
|
107
|
+
"
|
|
108
|
+
|
|
109
|
+
- name: Upload pip-path reports
|
|
110
|
+
if: always()
|
|
111
|
+
uses: actions/upload-artifact@v4
|
|
112
|
+
with:
|
|
113
|
+
name: pip-path-junit
|
|
114
|
+
path: |
|
|
115
|
+
cli-junit.xml
|
|
116
|
+
plugin-junit.xml
|
|
117
|
+
|
|
118
|
+
terraform:
|
|
119
|
+
name: terraform fmt + validate
|
|
120
|
+
runs-on: ubuntu-latest
|
|
121
|
+
steps:
|
|
122
|
+
- uses: actions/checkout@v4
|
|
123
|
+
|
|
124
|
+
- name: Format check
|
|
125
|
+
run: |
|
|
126
|
+
podman run --rm -v "$PWD:/work:Z" -w /work \
|
|
127
|
+
docker.io/hashicorp/terraform:latest -chdir=infra/terraform fmt -check -recursive
|
|
128
|
+
|
|
129
|
+
- name: Init + validate example
|
|
130
|
+
run: |
|
|
131
|
+
podman run --rm -v "$PWD:/work:Z" -w /work \
|
|
132
|
+
docker.io/hashicorp/terraform:latest -chdir=infra/terraform/examples/basic init -backend=false -input=false
|
|
133
|
+
podman run --rm -v "$PWD:/work:Z" -w /work \
|
|
134
|
+
docker.io/hashicorp/terraform:latest -chdir=infra/terraform/examples/basic validate
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
name: release
|
|
2
|
+
|
|
3
|
+
# Triggered by a semver tag (e.g. v0.1.0). Builds the Python distribution and the
|
|
4
|
+
# container image, publishes the image to GHCR, and attaches the dist to the
|
|
5
|
+
# GitHub Release. Everything is built inside containers.
|
|
6
|
+
|
|
7
|
+
on:
|
|
8
|
+
push:
|
|
9
|
+
tags:
|
|
10
|
+
- "v*.*.*"
|
|
11
|
+
|
|
12
|
+
permissions:
|
|
13
|
+
contents: write
|
|
14
|
+
packages: write
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
build-dist:
|
|
18
|
+
name: build python distribution
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@v4
|
|
22
|
+
|
|
23
|
+
- name: Build sdist + wheel (containerized)
|
|
24
|
+
run: |
|
|
25
|
+
podman run --rm -v "$PWD:/work:Z" -w /work \
|
|
26
|
+
docker.io/library/python:3.12-slim bash -euc "
|
|
27
|
+
pip install -q build
|
|
28
|
+
python -m build
|
|
29
|
+
"
|
|
30
|
+
|
|
31
|
+
- name: Upload distribution artifacts
|
|
32
|
+
uses: actions/upload-artifact@v4
|
|
33
|
+
with:
|
|
34
|
+
name: dist
|
|
35
|
+
path: dist/*
|
|
36
|
+
|
|
37
|
+
publish-image:
|
|
38
|
+
name: publish container image to GHCR
|
|
39
|
+
runs-on: ubuntu-latest
|
|
40
|
+
needs: build-dist
|
|
41
|
+
steps:
|
|
42
|
+
- uses: actions/checkout@v4
|
|
43
|
+
|
|
44
|
+
- name: Compute image refs
|
|
45
|
+
id: meta
|
|
46
|
+
run: |
|
|
47
|
+
# ghcr.io/coldqubit/shotgate when hosted at github.com/coldqubit/shotgate
|
|
48
|
+
IMG="ghcr.io/${GITHUB_REPOSITORY,,}"
|
|
49
|
+
VERSION="${GITHUB_REF_NAME#v}" # strip leading 'v' from the tag
|
|
50
|
+
SHA="${GITHUB_SHA::12}" # short git sha
|
|
51
|
+
{
|
|
52
|
+
echo "image=${IMG}"
|
|
53
|
+
echo "version=${VERSION}"
|
|
54
|
+
echo "sha=${SHA}"
|
|
55
|
+
} >> "$GITHUB_OUTPUT"
|
|
56
|
+
|
|
57
|
+
- name: Log in to GHCR
|
|
58
|
+
run: |
|
|
59
|
+
echo "${{ secrets.GITHUB_TOKEN }}" | \
|
|
60
|
+
podman login ghcr.io -u "${{ github.actor }}" --password-stdin
|
|
61
|
+
|
|
62
|
+
- name: Build and push runtime image (aer)
|
|
63
|
+
env:
|
|
64
|
+
IMG: ${{ steps.meta.outputs.image }}
|
|
65
|
+
VERSION: ${{ steps.meta.outputs.version }}
|
|
66
|
+
SHA: ${{ steps.meta.outputs.sha }}
|
|
67
|
+
run: |
|
|
68
|
+
# Tags: semver version, git sha, and latest.
|
|
69
|
+
podman build \
|
|
70
|
+
-t "${IMG}:${VERSION}" \
|
|
71
|
+
-t "${IMG}:${SHA}" \
|
|
72
|
+
-t "${IMG}:latest" .
|
|
73
|
+
podman push "${IMG}:${VERSION}"
|
|
74
|
+
podman push "${IMG}:${SHA}"
|
|
75
|
+
podman push "${IMG}:latest"
|
|
76
|
+
|
|
77
|
+
- name: Build and push IBM variant (aer + qiskit-ibm-runtime)
|
|
78
|
+
env:
|
|
79
|
+
IMG: ${{ steps.meta.outputs.image }}
|
|
80
|
+
VERSION: ${{ steps.meta.outputs.version }}
|
|
81
|
+
run: |
|
|
82
|
+
# Cloud/QPU-capable image so the ibm backend is runnable from a pull.
|
|
83
|
+
podman build --build-arg SHOTGATE_EXTRAS="aer,ibm" \
|
|
84
|
+
-t "${IMG}:${VERSION}-ibm" \
|
|
85
|
+
-t "${IMG}:latest-ibm" .
|
|
86
|
+
podman push "${IMG}:${VERSION}-ibm"
|
|
87
|
+
podman push "${IMG}:latest-ibm"
|
|
88
|
+
|
|
89
|
+
publish-pypi:
|
|
90
|
+
name: publish to PyPI (trusted publishing)
|
|
91
|
+
runs-on: ubuntu-latest
|
|
92
|
+
needs: build-dist
|
|
93
|
+
# OIDC, no API token. GitHub mints a signed identity token that PyPI verifies
|
|
94
|
+
# against a configured trusted publisher. One-time setup on PyPI before the
|
|
95
|
+
# first tag: pypi.org -> the `shotgate` project (or a "pending publisher" if it
|
|
96
|
+
# does not exist yet) -> add a GitHub publisher with
|
|
97
|
+
# owner: coldqubit repo: shotgate workflow: release.yml environment: pypi
|
|
98
|
+
environment:
|
|
99
|
+
name: pypi
|
|
100
|
+
url: https://pypi.org/p/shotgate
|
|
101
|
+
permissions:
|
|
102
|
+
id-token: write
|
|
103
|
+
steps:
|
|
104
|
+
- name: Download distribution artifacts
|
|
105
|
+
uses: actions/download-artifact@v4
|
|
106
|
+
with:
|
|
107
|
+
name: dist
|
|
108
|
+
path: dist
|
|
109
|
+
|
|
110
|
+
- name: Publish to PyPI
|
|
111
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
112
|
+
with:
|
|
113
|
+
packages-dir: dist
|
|
114
|
+
|
|
115
|
+
github-release:
|
|
116
|
+
name: create github release
|
|
117
|
+
runs-on: ubuntu-latest
|
|
118
|
+
needs: [build-dist, publish-image, publish-pypi]
|
|
119
|
+
steps:
|
|
120
|
+
- uses: actions/checkout@v4
|
|
121
|
+
- uses: actions/download-artifact@v4
|
|
122
|
+
with:
|
|
123
|
+
name: dist
|
|
124
|
+
path: dist
|
|
125
|
+
- name: Create release
|
|
126
|
+
uses: softprops/action-gh-release@v2
|
|
127
|
+
with:
|
|
128
|
+
files: dist/*
|
|
129
|
+
generate_release_notes: true
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
.eggs/
|
|
6
|
+
dist/
|
|
7
|
+
build/
|
|
8
|
+
.venv/
|
|
9
|
+
venv/
|
|
10
|
+
|
|
11
|
+
# Test / coverage / type / lint caches
|
|
12
|
+
.pytest_cache/
|
|
13
|
+
.coverage
|
|
14
|
+
coverage.xml
|
|
15
|
+
htmlcov/
|
|
16
|
+
.mypy_cache/
|
|
17
|
+
.ruff_cache/
|
|
18
|
+
|
|
19
|
+
# shotgate reports
|
|
20
|
+
report.xml
|
|
21
|
+
report.json
|
|
22
|
+
summary.md
|
|
23
|
+
*.shotgate.json
|
|
24
|
+
|
|
25
|
+
# Terraform
|
|
26
|
+
infra/terraform/**/.terraform/
|
|
27
|
+
infra/terraform/**/*.tfstate
|
|
28
|
+
infra/terraform/**/*.tfstate.*
|
|
29
|
+
infra/terraform/**/.terraform.lock.hcl
|
|
30
|
+
crash.log
|
|
31
|
+
|
|
32
|
+
# QEMU/KVM artifacts (downloaded images, overlays, seeds)
|
|
33
|
+
infra/qemu/.cache/
|
|
34
|
+
*.qcow2
|
|
35
|
+
seed.iso
|
|
36
|
+
|
|
37
|
+
# Editor / OS
|
|
38
|
+
.idea/
|
|
39
|
+
.vscode/
|
|
40
|
+
.DS_Store
|
|
41
|
+
|
|
42
|
+
# Stray caches (e.g. XDG cache when running python in a container with cwd HOME)
|
|
43
|
+
.cache/
|
|
44
|
+
|
|
45
|
+
# Local AI-assistant context (not part of the project)
|
|
46
|
+
CLAUDE.md
|
|
47
|
+
CLAUDE.local.md
|
|
48
|
+
.claude/
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Reference GitLab CI for gating a pipeline on a shotgate quantum workflow.
|
|
2
|
+
#
|
|
3
|
+
# Copy this into your own repo. It PULLS the published image (no build step) and runs
|
|
4
|
+
# the gate as a container job, emitting a JUnit report so the stage turns red when a
|
|
5
|
+
# statistical assertion fails. Exit-code contract: 0 = pass, 1 = a gate failed,
|
|
6
|
+
# 2 = bad config. The contract matches the GitHub Actions and Jenkins references.
|
|
7
|
+
|
|
8
|
+
stages:
|
|
9
|
+
- quantum
|
|
10
|
+
|
|
11
|
+
variables:
|
|
12
|
+
SHOTGATE_IMAGE: "ghcr.io/coldqubit/shotgate:latest"
|
|
13
|
+
WORKFLOW: "examples/bell-state/workflow.yaml"
|
|
14
|
+
|
|
15
|
+
quantum-gate:
|
|
16
|
+
stage: quantum
|
|
17
|
+
image: "$SHOTGATE_IMAGE"
|
|
18
|
+
script:
|
|
19
|
+
# The image entrypoint is `shotgate`; GitLab overrides it, so call it explicitly.
|
|
20
|
+
- shotgate run "$WORKFLOW" --junit report.xml --json report.json
|
|
21
|
+
artifacts:
|
|
22
|
+
when: always
|
|
23
|
+
paths:
|
|
24
|
+
- report.json
|
|
25
|
+
reports:
|
|
26
|
+
junit: report.xml
|
|
27
|
+
|
|
28
|
+
# Cloud/QPU variant: switch to the :latest-ibm image and provide a token via a
|
|
29
|
+
# masked CI/CD variable (Settings -> CI/CD -> Variables: SHOTGATE_IBM_TOKEN).
|
|
30
|
+
#
|
|
31
|
+
# quantum-gate-qpu:
|
|
32
|
+
# stage: quantum
|
|
33
|
+
# image: "ghcr.io/coldqubit/shotgate:latest-ibm"
|
|
34
|
+
# script:
|
|
35
|
+
# - shotgate run examples/bell-state-hardware/workflow.yaml --backend ibm --junit report.xml
|
|
36
|
+
# artifacts:
|
|
37
|
+
# when: always
|
|
38
|
+
# reports:
|
|
39
|
+
# junit: report.xml
|
|
40
|
+
# rules:
|
|
41
|
+
# - if: '$SHOTGATE_IBM_TOKEN'
|
|
42
|
+
|
|
43
|
+
# Pip alternative (no image pull): install the package and gate with the CLI or the
|
|
44
|
+
# pytest plugin instead of pulling the container image.
|
|
45
|
+
#
|
|
46
|
+
# quantum-gate-pip:
|
|
47
|
+
# stage: quantum
|
|
48
|
+
# image: "python:3.12-slim"
|
|
49
|
+
# script:
|
|
50
|
+
# - pip install "shotgate[aer]"
|
|
51
|
+
# - shotgate run "$WORKFLOW" --junit report.xml # CLI path
|
|
52
|
+
# # or one pytest item per assertion (the pytest plugin):
|
|
53
|
+
# - pytest --shotgate "$WORKFLOW" --junitxml=report.xml
|
|
54
|
+
# artifacts:
|
|
55
|
+
# when: always
|
|
56
|
+
# reports:
|
|
57
|
+
# junit: report.xml
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here. The format is based on
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to
|
|
5
|
+
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
*Nothing yet.*
|
|
10
|
+
|
|
11
|
+
## [0.1.0] - 2026-06-10
|
|
12
|
+
|
|
13
|
+
> First public, tagged release. The codebase began on 2026-06-01 under the name `qforge`
|
|
14
|
+
> and was renamed to `shotgate`; it had no prior git tag, PyPI release, or published
|
|
15
|
+
> container image, so this is the project's first release of record. The capability
|
|
16
|
+
> baseline (workflows, oracles, backends, CLI, reporters, IaC, isolation) is listed under
|
|
17
|
+
> **Core capabilities** below; the entries above it are what changed on the way to release.
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- **Relicensed from AGPL-3.0-or-later to Apache-2.0.** The `LICENSE` file now carries the
|
|
22
|
+
verbatim Apache License 2.0 text, every `src/shotgate/**/*.py` SPDX header reads
|
|
23
|
+
`Apache-2.0`, and `pyproject.toml` declares `license = "Apache-2.0"` with the
|
|
24
|
+
`License :: OSI Approved :: Apache Software License` classifier. Apache-2.0 is permissive:
|
|
25
|
+
use, modification, and redistribution are allowed for any purpose, including commercial and
|
|
26
|
+
closed-source, provided the license and attribution notices are retained. The previous
|
|
27
|
+
network-copyleft (source-disclosure for hosted modified versions) no longer applies.
|
|
28
|
+
- **Renamed the project from `qforge` to `shotgate`.** The name `qforge` was already
|
|
29
|
+
taken (PyPI/crates) and raised a VS Code marketplace trademark concern. The package
|
|
30
|
+
(`src/shotgate`), CLI program, container image, environment variables
|
|
31
|
+
(`SHOTGATE_IBM_TOKEN`), and the workflow API version (`shotgate.dev/v1alpha1`) all
|
|
32
|
+
moved to the new name. The canonical home is `github.com/coldqubit/shotgate` and the
|
|
33
|
+
published image is `ghcr.io/coldqubit/shotgate`.
|
|
34
|
+
- **Pull-first usage.** Documentation now leads with `podman run
|
|
35
|
+
ghcr.io/coldqubit/shotgate …`; building from source is the contributor fallback.
|
|
36
|
+
- **Honest extras.** `braket` and `mitigation` are marked *planned* and removed from the
|
|
37
|
+
installable `all` extra, since no Braket backend or Mitiq integration ships yet.
|
|
38
|
+
`--backend braket` now fails fast at schema validation with a clear message.
|
|
39
|
+
- **Project identity and governance made consistent.** Committed files refer to the
|
|
40
|
+
project home as `coldqubit` and to the maintainer *role* rather than to a personal
|
|
41
|
+
account: the README maintainer note was rewritten, [`CODEOWNERS`](CODEOWNERS) now
|
|
42
|
+
points at the `@coldqubit/maintainers` team, and the contribution terms were aligned.
|
|
43
|
+
The `CONTRIBUTING.md` inbound-license statement, which incorrectly named the MIT
|
|
44
|
+
License, now correctly states Apache-2.0 and is expressed as a Developer Certificate of
|
|
45
|
+
Origin (DCO) sign-off.
|
|
46
|
+
|
|
47
|
+
### Added
|
|
48
|
+
|
|
49
|
+
- **Published container image** to GHCR on tag, tagged with the semver version, the
|
|
50
|
+
git SHA, and `latest` (release pipeline).
|
|
51
|
+
- **Reference CI for GitLab and Jenkins** (`.gitlab-ci.yml`, `Jenkinsfile`) that pull the
|
|
52
|
+
published image and emit JUnit, alongside the existing GitHub Actions example.
|
|
53
|
+
- **Hardened IBM/QPU backend**: robust counts extraction from named classical registers
|
|
54
|
+
(with a clear error on unexpected result shapes), corrected Runtime channel default,
|
|
55
|
+
a token-gated smoke test, and an `[ibm]`-baked image variant (build arg
|
|
56
|
+
`SHOTGATE_EXTRAS="aer,ibm"`, published as the `:…-ibm` image tag).
|
|
57
|
+
- **Noise-tolerant example** (`examples/bell-state-hardware/`) with relaxed thresholds
|
|
58
|
+
for real-device runs, plus a documented simulator-vs-QPU threshold split.
|
|
59
|
+
- **`docs/hardware-validation.md`**: a step-by-step plan and acceptance matrix for
|
|
60
|
+
validating the statistical gates on real IBM quantum hardware (v0.2 milestone).
|
|
61
|
+
- **`GOVERNANCE.md` and `MAINTAINERS.md`**: how decisions are made (lazy consensus,
|
|
62
|
+
Architecture Decision Records for substantial changes, single maintainer today and
|
|
63
|
+
structured to grow) and who maintains the project, including the concrete path for a
|
|
64
|
+
co-maintainer to join.
|
|
65
|
+
- **Automated PyPI publishing** via trusted publishing (OIDC, no stored token): the tagged
|
|
66
|
+
release pipeline builds the sdist + wheel and publishes them to PyPI alongside the GHCR
|
|
67
|
+
image and the GitHub Release, so `pip install shotgate[aer]` resolves from a tag.
|
|
68
|
+
- **README terminal visual** (`docs/assets/bell-state-demo.svg`): a branded render of the
|
|
69
|
+
`examples/bell-state` gate output (five passing oracles), plus a live CI status badge.
|
|
70
|
+
|
|
71
|
+
> The `ibm` backend remains **implemented but not yet validated on real hardware**.
|
|
72
|
+
|
|
73
|
+
### Core capabilities
|
|
74
|
+
|
|
75
|
+
> The feature baseline, first built under the name `qforge` (workflow API `qforge.dev/v1alpha1`,
|
|
76
|
+
> since renamed to `shotgate.dev/v1alpha1`).
|
|
77
|
+
|
|
78
|
+
- **Declarative workflows** (`qforge.dev/v1alpha1`): strict, Kubernetes-style YAML
|
|
79
|
+
schema for "quantum workflow as code" with workflow-level backend defaults.
|
|
80
|
+
- **Statistical assertion oracles**: `distribution_tvd`, `hellinger_fidelity`,
|
|
81
|
+
`chi_square` (Pearson goodness-of-fit), `state_probability`, `allowed_states`.
|
|
82
|
+
- **Pure-Python statistics core**: total variation distance, Hellinger fidelity, and a
|
|
83
|
+
from-scratch chi-square survival function via the regularised incomplete gamma
|
|
84
|
+
function (no SciPy/numpy dependency).
|
|
85
|
+
- **Pluggable backends**: `Backend` ABC + lazy registry; `local-aer` (Qiskit Aer) and
|
|
86
|
+
an `ibm` (Qiskit Runtime) backend. SDKs imported lazily so the core stays light.
|
|
87
|
+
- **CLI**: `shotgate run` (CI quality gate, exit 0/1/2), `validate`, `backends`.
|
|
88
|
+
- **Reporters**: JUnit XML, JSON, Markdown summary, and Rich console output.
|
|
89
|
+
- **Telemetry**: per-job circuit width/depth/size/op-counts and wall-clock runtime.
|
|
90
|
+
- **Container-native tooling**: multi-stage `Containerfile` (non-root runtime + test
|
|
91
|
+
stage) and a Podman/QEMU `Makefile`.
|
|
92
|
+
- **KVM/QEMU isolation tier**: `infra/qemu` boots an ephemeral Fedora micro-VM
|
|
93
|
+
(cloud-init, copy-on-write overlay) that runs shotgate in Podman inside the VM.
|
|
94
|
+
- **Terraform IaC module**: express a quantum quality gate as a `terraform_data`
|
|
95
|
+
resource driven by the shotgate container.
|
|
96
|
+
- **CI/CD**: Podman-based GitHub Actions for lint, core + integration tests, example
|
|
97
|
+
gates, Terraform validation, and a tagged release pipeline (dist + GHCR image).
|
|
98
|
+
- **Docs**: solution architecture, pipeline schema, workflow spec, assertion catalog
|
|
99
|
+
(with the math), getting-started guide, and ADRs.
|
|
100
|
+
- **Examples**: Bell state, 3-qubit GHZ, and 2-qubit Grover workflows.
|
|
101
|
+
|
|
102
|
+
[Unreleased]: https://github.com/coldqubit/shotgate/compare/v0.1.0...HEAD
|
|
103
|
+
[0.1.0]: https://github.com/coldqubit/shotgate/releases/tag/v0.1.0
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Code owners for shotgate. The project is developed under the coldqubit project home
|
|
2
|
+
# and is maintained today by one person; MAINTAINERS.md is the source of truth for the
|
|
3
|
+
# current roster, and GOVERNANCE.md for how that roster changes.
|
|
4
|
+
#
|
|
5
|
+
# Ownership points at the @coldqubit/maintainers team rather than any personal account,
|
|
6
|
+
# so review requests track the maintainer role, not an individual. Create that team in
|
|
7
|
+
# the coldqubit organization on GitHub (members = the people in MAINTAINERS.md) for
|
|
8
|
+
# these entries to resolve.
|
|
9
|
+
* @coldqubit/maintainers
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Code of Conduct
|
|
2
|
+
|
|
3
|
+
## Our pledge
|
|
4
|
+
|
|
5
|
+
We as members, contributors, and leaders pledge to make participation in the shotgate
|
|
6
|
+
community a harassment-free experience for everyone, regardless of age, body size,
|
|
7
|
+
visible or invisible disability, ethnicity, sex characteristics, gender identity and
|
|
8
|
+
expression, level of experience, education, socio-economic status, nationality,
|
|
9
|
+
personal appearance, race, religion, or sexual identity and orientation.
|
|
10
|
+
|
|
11
|
+
We pledge to act and interact in ways that contribute to an open, welcoming, diverse,
|
|
12
|
+
inclusive, and healthy community.
|
|
13
|
+
|
|
14
|
+
## Our standards
|
|
15
|
+
|
|
16
|
+
Examples of behavior that contributes to a positive environment:
|
|
17
|
+
|
|
18
|
+
- Demonstrating empathy and kindness toward other people
|
|
19
|
+
- Being respectful of differing opinions, viewpoints, and experiences
|
|
20
|
+
- Giving and gracefully accepting constructive feedback
|
|
21
|
+
- Focusing on what is best for the overall community
|
|
22
|
+
|
|
23
|
+
Unacceptable behavior includes harassment, trolling, insulting or derogatory comments,
|
|
24
|
+
public or private harassment, publishing others' private information without consent,
|
|
25
|
+
and other conduct which could reasonably be considered inappropriate.
|
|
26
|
+
|
|
27
|
+
## Enforcement
|
|
28
|
+
|
|
29
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to
|
|
30
|
+
the maintainers listed in `CODEOWNERS`. All complaints will be reviewed and
|
|
31
|
+
investigated promptly and fairly. Maintainers will respect the privacy and security of
|
|
32
|
+
the reporter.
|
|
33
|
+
|
|
34
|
+
## Attribution
|
|
35
|
+
|
|
36
|
+
This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org),
|
|
37
|
+
version 2.1.
|