Files
acdl/.github/workflows/platform-test.yml
T
Jon Chery 4bd07a4fae feat(P27): validated per-module examples (D-058) + schema glob fix
Add modules/<name>/examples/ directories with simple.yaml + complex.yaml
(+ mysql.yaml for RDS) for every primitive and module pattern. All 25
example contracts validate against schemas/contract.schema.json. Update
the contract schema to allow object/array input values (for env vars).
Fix the platform-test schema-validation glob to modules/*/*/examples/*.yaml
to match the nested l1/l2 path structure. Update the microservice sample
contract note (env objects now permitted by the schema).

---ci---
project: acdl
phase: 27
milestone: v1.7
status: execute
---/ci---
2026-07-22 20:22:45 +00:00

146 lines
5.9 KiB
YAML

# ACDL Platform Test Pipeline — GitHub Actions (production)
#
# Runs on PRs to main. Replaces ci.yml for PRs (ci.yml stays for push-to-main).
# Four stages: lint, unit-test, integration-test, schema-validation.
#
# Shell reproducibility: scripts/run_ci.sh runs lint + test + check-only locally.
# The integration-test stage runs run_platform.sh --check-only for every
# contracts/*.yaml file. The schema-validation stage validates schemas, module
# interfaces, compositions, and example contracts.
name: acdl-platform-test
on:
pull_request:
branches: [main]
jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Compile all Python files
run: |
python3 -m py_compile \
core/confidence_signal.py \
core/outbox_writer.py \
core/contract_resolver.py \
core/environment_check.py \
core/output_publisher.py \
core/lambda/contract_ingestor.py \
adapters/terraform/adapter.py \
adapters/terraform/policy/checkov_adapter.py \
adapters/wiz/wiz_adapter.py \
adapters/kyverno/kyverno_adapter.py \
scripts/push_consumer_image.py
unit-test:
name: Unit tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install test dependencies
run: pip install -r requirements-test.txt
- name: Run pytest
run: python3 -m pytest tests/ -v --tb=short
integration-test:
name: Integration test (all sample contracts)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install runtime dependencies
run: pip install jsonschema pyyaml boto3
- name: Run platform check-only for every sample contract
run: |
for contract in contracts/*.yaml; do
echo "--- Testing $contract ---"
bash scripts/run_platform.sh --check-only "$contract"
done
schema-validation:
name: Schema + module validation
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install dependencies
run: pip install jsonschema pyyaml
- name: Validate all schemas
run: |
python3 -c "
import json, glob, jsonschema
for schema_file in glob.glob('schemas/*.json'):
if 'contract.schema' in schema_file:
continue # has no self-validation
schema = json.load(open(schema_file))
# self-validate if it has a \$id
try:
jsonschema.Draft202012Validator.check_schema(schema)
except jsonschema.SchemaError as e:
raise SystemExit(f'{schema_file}: {e}')
print(f'{schema_file}: valid')
"
- name: Validate all module interfaces against stack.schema.json
run: |
python3 -c "
import json, glob, jsonschema, os
stack_schema = json.load(open('schemas/stack.schema.json'))
for iface_file in glob.glob('modules/l1/*/interface.json'):
try:
iface = json.load(open(iface_file))
# Validate basic structure (name, version, kind, type, inputs, outputs)
assert 'name' in iface, f'{iface_file}: missing name'
assert 'version' in iface, f'{iface_file}: missing version'
assert 'kind' in iface, f'{iface_file}: missing kind'
assert iface['kind'] == 'l1', f'{iface_file}: expected kind=l1'
assert 'type' in iface, f'{iface_file}: missing type'
assert 'inputs' in iface, f'{iface_file}: missing inputs'
assert 'outputs' in iface, f'{iface_file}: missing outputs'
print(f'{iface_file}: valid L1')
except Exception as e:
raise SystemExit(f'{iface_file}: {e}')
for comp_file in glob.glob('modules/l2/*/composition.json'):
try:
comp = json.load(open(comp_file))
assert 'name' in comp, f'{comp_file}: missing name'
assert 'version' in comp, f'{comp_file}: missing version'
assert 'kind' in comp, f'{comp_file}: missing kind'
assert comp['kind'] == 'l2', f'{comp_file}: expected kind=l2'
assert 'children' in comp, f'{comp_file}: missing children'
assert 'wires' in comp, f'{comp_file}: missing wires'
assert 'outputs' in comp, f'{comp_file}: missing outputs'
print(f'{comp_file}: valid L2')
except Exception as e:
raise SystemExit(f'{comp_file}: {e}')
"
- name: Validate module example contracts
run: |
python3 -c "
import json, yaml, glob, jsonschema
schema = json.load(open('schemas/contract.schema.json'))
# Validate example contracts if they exist
for example in glob.glob('modules/*/*/examples/*.yaml'):
try:
contract = yaml.safe_load(open(example))
jsonschema.validate(contract, schema)
print(f'{example}: valid contract')
except Exception as e:
print(f'{example}: SKIP (not a contract or invalid: {e})')
# Also validate all sample contracts in contracts/
for contract_file in glob.glob('contracts/*.yaml'):
contract = yaml.safe_load(open(contract_file))
jsonschema.validate(contract, schema)
print(f'{contract_file}: valid contract')
"