Depth-tracked regulatory audit primitives for future FHE-CKKS execution.
Project description
regaudit-fhe
Depth-tracked regulatory audit primitives for privacy-preserving AI audits.
regaudit-fhe provides a plaintext slot-vector reference model, TenSEAL
CKKS backend support, signed audit envelopes, schema validation, and
regulatory audit-evidence helpers.
The default execution path is plaintext. Install the [fhe] extra to
enable the TenSEAL CKKS backend where supported. OpenFHE is not
included in this repository.
Maintained by VaultBytes Innovations Ltd. Dual-licensed: AGPL-3.0-or-later (default — see LICENSE) or VaultBytes Commercial License for deployments where AGPL is not workable (see LICENSE-COMMERCIAL.md; contact b@vaultbytes.com).
What it is for
┌──────────────┐ encrypted inputs ┌────────────────┐
│ Regulated │ ──────────────────────────► │ regaudit-fhe │
│ AI vendor │ (labels, preds, PHI, │ d=6 CKKS audit │
│ (the client) │ protected attrs) │ primitives │
└──────────────┘ └──────┬─────────┘
▲ │
│ │ encrypted
│ sealed envelope │ aggregate
│ (JSON + receipt) │ scalars only
│ ▼
│ ┌────────────────┐
└───────────────────────────────────► │ Regulator / │
│ external │
decrypt + verify receipt │ auditor │
└────────────────┘
Two audiences are served by the same surface area:
| Audience | Role | What they run |
|---|---|---|
| Client | Audited entity (vendor / operator). | audit_* primitives, regaudit-fhe audit .... |
| Regulator | External or in-house auditor. | verify_envelope_or_raise(env, trust_store=...) against a TrustStore; regaudit-fhe verify --trusted-keys .... |
A run produces an audit envelope (JSON) with a SHA-256 receipt. The client archives it, ships it to the regulator, or both. The regulator recomputes the receipt to detect tampering between issuance and review.
The six primitives
| Module | API | Depth | Use case (technical evidence supporting…) |
|---|---|---|---|
egf_imss |
audit_fairness |
4 | NYC LL144, EU AI Act §10/§15, Colorado AI Act, CFPB workflows. |
etk_fpa_hbc |
audit_provenance |
3 | EU AI Act §10, 21 CFR Part 11, GDPR §22, HIPAA workflows. |
esc_cia |
audit_concordance |
4 | FDA SaMD oncology PCCP, EU AI Act §15, EMA workflows. |
ecp_qssp |
audit_calibration |
3 | FDA SaMD UQ, EU AI Act §15, ISO/IEC 23053, UNECE WP.29 workflows. |
ew1_cdsf |
audit_drift |
3 | EU AI Act §15, FDA SaMD PCCP, Basel III workflows. |
ecmd_jps |
audit_disagreement |
5 | OCC SR 11-7, EU AI Act §15, FDA SaMD PCCP workflows. |
Compliance scope and disclaimer.
regaudit-fheproduces technical evidence — encrypted scalars, signed envelopes, parameter-set hashes, depth-budget attestations — that may support compliance workflows in the jurisdictions above. It does not constitute legal compliance, conformity assessment, regulatory acceptance, or a recognised audit. Read COMPLIANCE.md for the binding scope statement and the "what-it-does-NOT-prove" mapping per regulation.
Each primitive's depth budget — the number of multiplicative levels it
consumes inside the d=6 CKKS circuit — is shown above. All six fit
under six on the TenSEAL backend, leaving headroom for downstream
commit-and-verify chaining. The values below are observed at runtime
on the real CKKS execution path; the source of truth is
benchmarks/results/SUMMARY.md and the last_depth(name) /
last_depths() accessors in regaudit_fhe.fhe.primitives (the
underlying state is held in a ContextVar so concurrent encrypted
calls do not race on the depth record).
Depth budget visualisation (each ▮ = 1 consumed level; observed on TenSEAL)
primitive 1 2 3 4 5 6
───────────────────────────────────
audit_fairness ▮ ▮ . . . . 2 of 6 (encrypt + mul_pt + mul_scalar)
audit_provenance ▮ ▮ . . . . 2 of 6 (encrypt + mul_pt fold per bucket)
audit_drift ▮ ▮ ▮ . . . 3 of 6 (mm_pt CDF + ct×ct square)
audit_calibration ▮ ▮ ▮ ▮ . . 4 of 6 (mul_pt scale + sign_poly_d3)
audit_disagreement ▮ ▮ ▮ ▮ ▮ . 5 of 6 (deg-3 poly + pairwise sq + scale)
audit_concordance ▮ ▮ ▮ ▮ ▮ ▮ 6 of 6 (rotate via mm_pt + sign_poly_d3
+ ct×ct event mask)
Each primitive's full specification, including its algorithm, depth
breakdown, and security analysis, is in
docs/specs/.
Install
pip install regaudit-fhe
The plaintext model that runs the depth-budgeted slot-vector circuits
(used for testing, oracles, and CI) requires only numpy>=1.26. The
encrypted execution path lives behind the optional [fhe] extra:
pip install regaudit-fhe[fhe] # adds the TenSEAL CKKS backend
Quick start
Client side — produce an audit envelope
import numpy as np
import regaudit_fhe as rf
y_true = np.array([1, 0, 1, 1, 0, 1, 0, 0], dtype=float)
y_pred = np.array([1, 0, 1, 0, 0, 1, 1, 0], dtype=float)
group_a = np.array([1, 1, 1, 1, 0, 0, 0, 0], dtype=float)
group_b = 1.0 - group_a
report = rf.audit_fairness(y_true, y_pred, group_a, group_b, threshold=0.1)
print(report.demographic_parity_diff, report.threshold_breached)
# Long-lived issuer key in production; ephemeral for demos.
signer = rf.Signer.generate(issuer="acme-bank", key_id="acme-2026-04")
envelope = rf.envelope("fairness", report, signer=signer)
print(envelope.to_json()) # ship this to the regulator
Regulator side — verify against a trust store (recommended)
import regaudit_fhe as rf
# trust_store.json maps key_id -> PEM-encoded Ed25519 public key.
# Optional fields: "revoked": [...], "parameter_set_pins": {key_id: hex}.
trust_store = rf.TrustStore.from_json("trust_store.json")
env = rf.AuditEnvelope.from_dict(received_payload)
try:
outcome = rf.verify_envelope_or_raise(env, trust_store=trust_store)
except rf.UntrustedIssuer: # key_id unknown OR embedded PEM mismatch
...
except rf.RevokedIssuer: # key_id is in trust_store.revoked
...
except rf.WrongParameterSet: # parameter_set_hash != pinned value
...
except rf.HashMismatch: # body changed since signing
...
except rf.InvalidSignature: # Ed25519 verify failed
...
# All five subclass rf.EnvelopeVerificationError.
verify_envelope_or_raise returns the underlying VerificationOutcome
on success. Use it instead of the legacy bool-return path whenever you
need to react differently to each failure reason.
Why a trust store is required.
verify_receipt(env)(no arguments) only checks that the embedded SHA-256 receipt matches the canonical body and that the Ed25519 signature verifies against the embedded public key. That proves the bytes have not changed in transit — it does not prove the envelope was produced by an auditor the regulator approved. Calling withouttrusted_keysemits a one-timeUserWarningso integrators do not silently rely on the weak path.
Same flow, command line
# Client
echo '{"y_true":[1,0,1,1],"y_pred":[1,0,0,0],"group_a":[1,1,0,0],"group_b":[0,0,1,1]}' \
> input.json
regaudit-fhe audit fairness -i input.json -o envelope.json
# Regulator
regaudit-fhe verify -i envelope.json --trusted-keys trust_store.json --strict
The regulator command exits 0 on success, 1 on a typed verification
failure (with a JSON body naming the reason), and 2 on bad CLI input.
--strict without --trusted-keys is a hard error: the strict path
demands an explicit trust store.
regaudit-fhe audit <primitive> --schema prints the JSON shape that
each primitive expects.
The HTTP server is NOT a privacy boundary by itself. The default execution path is plaintext; the server runs in-process. Encrypted execution requires the
[fhe]extra AND CKKS secret-key custody held off-host. Bearer-token authentication uses constant-time hashed comparison (no token timing leak) andREGAUDIT_FHE_DEV_MODE=1refuses to start on a non-loopback bind, but issuer authenticity still relies on the verifier's trust store. Read docs/DEPLOYMENT.md and docs/THREAT_MODEL.md before exposing publicly.
Audit envelope
Every audit_* call can be wrapped into a regulator-facing JSON
envelope by regaudit_fhe.envelope(...):
{
"schema": "regaudit-fhe.report.v1",
"library_version": "current release",
"primitive": "fairness",
"backend": "plaintext-slotvec",
"parameter_set_hash": "sha256:6b8aedc173e2c94e…",
"input_commitments": {
"y_true": "sha256:a5c4…",
"y_pred": "sha256:7e91…"
},
"result": {
"max_gap": 0.0312,
"threshold_breached": false
},
"receipt": {
"sha256": "sha256:9f3c…b4a7",
"signature_alg": "Ed25519",
"signature": "base64:MEUCIQDX…",
"key_id": "auditor-key-2026-04"
}
}
schema, parameter_set_hash, and input_commitments give a
regulator the exact citation, parameter binding, and input fingerprint
they need. Unsigned SHA-256 receipts are useful for tamper evidence
only; signed receipts (the default since regaudit-fhe v0.0.2)
provide issuer authenticity when the verifier trusts the signing key.
Examples
The examples/ folder ships four end-to-end flows:
| File | Flow |
|---|---|
01_client_local_audit.py |
Internal audit on synthetic data; archive JSON locally. |
02_client_to_regulator.py |
Build a regulator submission bundle. |
03_regulator_verify.py |
Verify every envelope inside a bundle against a TrustStore; surfaces typed failure reasons. |
04_cli_roundtrip.sh |
Pure CLI: input → audit → verify, no Python knowledge required. |
Run any of them after pip install -e .[dev].
Layout
src/regaudit_fhe/
_slot.py plaintext SlotVec model with depth-budget enforcement
_validation.py finite/binary/length input guards
cli.py regaudit-fhe CLI entrypoint
reports.py audit envelope: canonical JSON, parameter-set hash,
input commitments, Ed25519 signing,
verify_envelope_or_raise()
schemas.py JSON Schema loader + validator
trust.py TrustStore + typed verification exceptions
(UntrustedIssuer, RevokedIssuer, WrongParameterSet,
HashMismatch, InvalidSignature, TimestampInvalid)
schemas/ bundled Draft-2020-12 schemas (one per input/output + envelope)
server.py hardened FastAPI HTTP audit server
egf_imss.py fairness primitive
etk_fpa_hbc.py provenance primitive
esc_cia.py concordance primitive
ecp_qssp.py calibration primitive
ew1_cdsf.py drift primitive
ecmd_jps.py disagreement primitive
fhe/ TenSEAL CKKS encrypted backend (optional [fhe] extra):
context.py build_d6_context, CKKSContext
params.py validated CKKSParams
slot_vec.py EncryptedSlotVec mirroring the plaintext SlotVec API
primitives.py encrypted variants of every audit primitive
docs/specs/ per-primitive technical specifications
docs/THREAT_MODEL.md roles, key custody, per-primitive public-surface tables
docs/COMPLIANCE.md regulator-facing scope statement and disclaimers
docs/DEPLOYMENT.md server hardening guide + production checklist
docs/SUPPLY_CHAIN.md Sigstore verification, SBOM, reproducible build notes
docs/roadmap/ design notes for non-shipping work
schemas/ source-of-truth JSON Schemas
tests/ unit, integration, edge-case, property-based, schema, security
examples/ client + regulator end-to-end flows
benchmarks/ d=6 CKKS wall-clock + memory benchmarks
JSON schemas
Every primitive input, primitive output, and the audit envelope itself
ships with a Draft-2020-12 JSON Schema under schemas/.
Auditors and integrators can pin specific schema versions and reject
payloads that do not conform.
regaudit-fhe schema --list
regaudit-fhe schema fairness.input
regaudit-fhe schema envelope
The CLI and HTTP server validate every request body against the matching schema before invoking the audit primitive; failures return HTTP 422 / CLI exit-code 2 with a structured pointer to the offending field. Programmatic access:
import regaudit_fhe as rf
rf.list_schemas() # all 13 names
rf.load_schema("fairness.input") # raw schema dict
rf.validate_input("fairness", payload) # raises rf.SchemaError on bad input
rf.validate_envelope(env_dict) # check a regulator-side envelope
Real CKKS benchmarks
The [fhe] extra ships a real TenSEAL CKKS backend; its measurements
are reproduced from benchmarks/results/SUMMARY.md (machine-readable
JSON in benchmarks/results/bench_fhe_<N>.json).
| Primitive | N | Slots | Depth obs/decl | Rotations | ct×ct | ct×pt | Runtime | RAM | Max abs err | Threshold flip |
|---|---|---|---|---|---|---|---|---|---|---|
| fairness | 2^14 | 8 192 | 1/4 | 36 | 0 | 6 | 0.33 s | 887 MB | 4.8 × 10⁻⁷ | 0.00% |
| provenance | 2^14 | 8 192 | 1/3 | 96 | 0 | 16 | 0.90 s | 896 MB | 1.1 × 10⁻⁵ | 0.00% |
| concordance | 2^14 | 8 192 | 5/5 | 36 | 8 | 3 | 5.26 s | 2.3 GB | 1.5 × 10⁻⁶ | 0.00% |
| calibration | 2^14 | 8 192 | 3/4 | 0 | 2 | 1 | 0.03 s | 2.3 GB | 0 | 0.00% |
| drift | 2^14 | 8 192 | 2/2 | 12 | 1 | 2 | 0.27 s | 2.3 GB | 2.2 × 10⁻⁶ | 0.00% |
| disagreement | 2^14 | 8 192 | 3/5 | 0 | 12 | 0 | 0.31 s | 2.3 GB | 1.2 × 10⁻⁸ | 0.00% |
| fairness | 2^15 | 16 384 | 1/4 | 36 | 0 | 6 | 0.74 s | 4.0 GB | 9.6 × 10⁻⁷ | 0.00% |
| provenance | 2^15 | 16 384 | 1/3 | 96 | 0 | 16 | 2.04 s | 4.1 GB | 5.2 × 10⁻⁶ | 0.00% |
| concordance | 2^15 | 16 384 | 5/5 | 36 | 8 | 3 | 13.91 s | 6.9 GB | 3.0 × 10⁻⁷ | 0.00% |
| calibration | 2^15 | 16 384 | 3/4 | 0 | 2 | 1 | 0.08 s | 6.9 GB | 0 | 0.00% |
| drift | 2^15 | 16 384 | 2/2 | 12 | 1 | 2 | 0.64 s | 6.9 GB | 7.1 × 10⁻⁶ | 0.00% |
| disagreement | 2^15 | 16 384 | 3/5 | 0 | 12 | 0 | 0.64 s | 6.6 GB | 1.3 × 10⁻⁸ | 0.00% |
Run yourself:
pip install regaudit-fhe[fhe]
python benchmarks/bench_fhe.py --rings 14 15 --reps 3
Add --rings 16 for N = 2^16 (slower; uses several GB of RAM).
The "Threshold flip" column is the rate at which CKKS noise causes the encrypted circuit to disagree with the plaintext circuit on a boolean breach decision over 10–20 trials with inputs sampled near the breach boundary. Zero flips across both rings means CKKS noise does not change a regulatory threshold decision at the audit precision targets.
Verify a fresh clone
The release gate is one shell block. Anything that fails this block is a release blocker:
git clone https://github.com/BAder82t/regaudit-fhe.git
cd regaudit-fhe
python -m venv .venv && source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install -e ".[dev]"
python -m py_compile src/regaudit_fhe/*.py src/regaudit_fhe/fhe/*.py tests/*.py
python -c "import regaudit_fhe; print(regaudit_fhe.__version__)"
regaudit-fhe --help
regaudit-fhe schema --list
pytest -q
CI runs an equivalent matrix on every push (see .github/workflows/ci.yml) and the badge at the top of this README reflects the latest result.
Production / regulator readiness — what is and isn't validated
The release gate above guarantees the package builds, imports, exposes the documented CLI / API, and passes its test suite. That is not the same as being validated for regulated production use. The matrix below is the honest current state.
| Property | Status |
|---|---|
| Python syntax + imports | Verified by CI on every push. |
| 309-test pytest suite | Verified by CI on every push (Linux py3.10–3.13 + macOS py3.12 / 3.13). |
| Coverage gate | --cov-fail-under=80 enforced in CI; baseline 84%. |
| Type checking | mypy gates CI: zero errors across 19 source files. |
| Static security | bandit (medium+) gates CI; CodeQL (security-and-quality) runs on push and weekly. |
| Lint | ruff check gates CI with E/F/W/B/S/UP/I/SIM/RUF/A rule set. |
| Real CKKS encrypted backend (TenSEAL) | Shipped under [fhe]; equivalence-tested. |
| OpenFHE CKKS backend (experimental) | Shipped under [openfhe]; registry-selectable; equivalence-tested for 5/6 |
primitives (concordance pending rectangular mm_pt). Not the verified reference. |
|
| External key custody (KMS / HSM) | CallableKeyProvider keeps the signing key off-host; fails closed on bad sig. |
| Differential-privacy output noise | Optional regaudit_fhe.dp (Laplace / Gaussian); signed dp block. Sensitivity is |
| the deployer's responsibility — the library calibrates, it does not bound. | |
| Generated API reference | pdoc HTML built in CI (docs.yml); see docs/API.md. |
| Signed audit envelope (Ed25519) | Shipped; canonical-JSON + tamper tests. |
| Trust store + typed verifier failures | TrustStore + six EnvelopeVerificationError subclasses; CLI --trusted-keys. |
| JSON Schemas | Shipped; validated on every CLI / API request. |
| Hardened HTTP server | Constant-time bearer compare, opaque key_id in logs, DEV_MODE non-loopback bind |
| refusal, scopes, rate limit, CORS, audit log. | |
| Concurrency-safe depth state | ContextVar-backed last_depth / last_depths; cross-thread / asyncio isolated. |
| Reproducible wheel | CI builds twice with pinned SOURCE_DATE_EPOCH, asserts SHA-256 stable. |
| Sigstore-signed wheel + sdist | Keyless OIDC bundles attached to every GitHub Release. |
| Real benchmarks at N=2^14, N=2^15 | Shipped; reproducible from benchmarks/bench_fhe.py. |
regaudit-fhe is a dependency you can bring into a compliance
workflow today; it is not, by itself, a finished compliance product.
COMPLIANCE.md lists what each primitive does NOT
prove, regulation by regulation.
Maturity and status
Description: Depth-tracked regulatory audit primitives for privacy-preserving AI audits.
Backends: TenSEAL CKKS is the verified reference backend (
regaudit_fhe.fhe). An experimental OpenFHE CKKS backend (regaudit_fhe.fhe.openfhe) is also selectable through the backend registry; it covers every primitive except encrypted concordance (which needs rectangularmm_pt). See docs/roadmap/openfhe_backend.md for the design note.
The current release ships:
- the plaintext SlotVec model with strict depth-budget enforcement,
- a TenSEAL CKKS backend that mirrors the SlotVec algebra and passes end-to-end ciphertext / plaintext equivalence tests,
- a pluggable backend registry (
regaudit_fhe.fhe.get_backend/available_backends) with an experimental OpenFHE CKKS backend that runs the same circuits via the Halevi–Shoup diagonal method, - the Ed25519-signed audit envelope with canonical-JSON rules, parameter-set hashing, and input commitments,
- a typed verifier surface —
TrustStore(key_id → PEM, optional revocation, optional parameter-set pinning) plusverify_envelope_or_raiseraisingUntrustedIssuer/RevokedIssuer/WrongParameterSet/HashMismatch/InvalidSignature/TimestampInvalidfor regulator-side use, - a key-custody seam —
CallableKeyProviderkeeps the Ed25519 signing key in a KMS/HSM, so only a public PEM and a sign-callable enter the audit host, - an optional differential-privacy output-perturbation layer
(
regaudit_fhe.dp: Laplace / Gaussian mechanisms, a basic-composition accountant, and a signeddpdisclosure block in the envelope), - JSON Schemas for every input, output, and the envelope itself,
- the hardened HTTP audit server with constant-time bearer-token
compare, opaque hashed key_id in logs, scopes, body-size limit,
rate limiting, structured logs, CORS controls, and a
DEV_MODEnon-loopback bind guard, - concurrency-safe depth recording via
ContextVarso concurrent encrypted requests cannot race on the depth state, - supply-chain controls: Trusted-Publisher PyPI release, Sigstore
keyless signing of the wheel + sdist, reproducible-build CI gate
(pinned
SOURCE_DATE_EPOCH, two builds, identical SHA), CycloneDX SBOM,pip-audit, CodeQL, weekly Dependabot.
Contributions are not accepted — see CONTRIBUTING.md.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file regaudit_fhe-0.0.8.tar.gz.
File metadata
- Download URL: regaudit_fhe-0.0.8.tar.gz
- Upload date:
- Size: 141.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fed2802f0e3c7d1427c5487209e5c64a93f86cdb2a09ecce9f7684d79214b59b
|
|
| MD5 |
cb4ec145c6cc6b80e766195fa1e3a8d3
|
|
| BLAKE2b-256 |
76327501321e8df9e3ae0670d764f6855ebae9ff7570b93a006a2fa6bbe2c7a7
|
Provenance
The following attestation bundles were made for regaudit_fhe-0.0.8.tar.gz:
Publisher:
publish.yml on BAder82t/regaudit-fhe
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
regaudit_fhe-0.0.8.tar.gz -
Subject digest:
fed2802f0e3c7d1427c5487209e5c64a93f86cdb2a09ecce9f7684d79214b59b - Sigstore transparency entry: 1857904662
- Sigstore integration time:
-
Permalink:
BAder82t/regaudit-fhe@b5ebb9a7fcb61c4b7fb83c7ffc45a748f0554897 -
Branch / Tag:
refs/tags/v0.0.8 - Owner: https://github.com/BAder82t
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@b5ebb9a7fcb61c4b7fb83c7ffc45a748f0554897 -
Trigger Event:
push
-
Statement type:
File details
Details for the file regaudit_fhe-0.0.8-py3-none-any.whl.
File metadata
- Download URL: regaudit_fhe-0.0.8-py3-none-any.whl
- Upload date:
- Size: 90.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
39eac52a618f0bd8363d2bd9dbbdbc334dfdcc8066c700bc2f9669b093278b66
|
|
| MD5 |
7c9d38dc6f539c4695cc8066fc214776
|
|
| BLAKE2b-256 |
9dde9be32cc722a1d6b7448c6aa766a49f9f6d95e6820f46ef02b3515983883f
|
Provenance
The following attestation bundles were made for regaudit_fhe-0.0.8-py3-none-any.whl:
Publisher:
publish.yml on BAder82t/regaudit-fhe
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
regaudit_fhe-0.0.8-py3-none-any.whl -
Subject digest:
39eac52a618f0bd8363d2bd9dbbdbc334dfdcc8066c700bc2f9669b093278b66 - Sigstore transparency entry: 1857904669
- Sigstore integration time:
-
Permalink:
BAder82t/regaudit-fhe@b5ebb9a7fcb61c4b7fb83c7ffc45a748f0554897 -
Branch / Tag:
refs/tags/v0.0.8 - Owner: https://github.com/BAder82t
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@b5ebb9a7fcb61c4b7fb83c7ffc45a748f0554897 -
Trigger Event:
push
-
Statement type: