07c0349131
Phase 24 — platform-lambda-and-contract-ingestion. - core/lambda/contract_ingestor.py: AWS Lambda handler invoked via Function URL (IAM auth). Parses JSON body, validates required fields, writes the contract to DynamoDB table acdl-contracts (PK consumerRepo, SK contractId#submittedAt, status submitted, ISO-8601 submittedAt). report_error action is a stub returning "error_report_prepared"; GitHub issue creation is wired in Phase 25. Returns 400 on missing fields / unknown action, 500 on error. Table name + GitHub-token secret ID come from env (set by Terraform). - core/lambda/__init__.py: empty package marker. - terraform/platform/main.tf: DynamoDB acdl-contracts (PITR, SSE via CMK), KMS customer-managed key with alias/acdl-platform, Secrets Manager secret acdl/github-token, IAM execution role (DynamoDB write + Secrets Manager read + KMS decrypt + CloudWatch logs), Lambda acdl-contract-ingestor (Python 3.12, handler contract_ingestor.lambda_handler), Function URL with AWS_IAM auth. State key platform/terraform.tfstate (distinct from spike/microservice). - terraform/platform/README.md: documents what it deploys, the state key, how to apply, and the cross-account invocation model. - terraform/platform/consumer_invoke_policy.json: ABAC-scoped policy template applied to consumer deploy roles during onboarding; grants lambda:InvokeFunctionUrl conditioned on aws:PrincipalTag/acdl:owner == consumerRepo. - tests/test_contract_ingestor.py: 11 tests (moto-backed DynamoDB mock) covering submit_contract put_item shape, report_error stub, missing-field 400, unknown action 400, the lambda_handler wrapper with a Function-URL-style event, dict body, default action, and internal-error 500. - docs/environments/index.md: new section documenting the cross-account contract-ingestion grant (one-way consumer→platform, D-051) and that onboarding now also grants the consumer deploy role InvokeFunctionUrl. - scripts/run_ci.sh, pipelines/ci.yaml, .gitea/workflows/ci.yml, .github/workflows/ci.yml: add core/lambda/contract_ingestor.py to the lint py_compile list. The two workflow YAMLs remain byte-identical. Verification: scripts/run_ci.sh passes all 3 stages (lint/test/check-only); python3 -m pytest tests/ -v passes all 213 tests (11 new + 202 existing). ---ci--- project: acdl phase: 24 milestone: v1.7 status: execute ---/ci---
69 lines
2.0 KiB
Bash
Executable File
69 lines
2.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# scripts/run_ci.sh - reproduce the CI pipeline locally.
|
|
#
|
|
# Mirrors the central pipeline contract (pipelines/ci.yaml) which both
|
|
# .gitea/workflows/ci.yml (Gitea Actions, dev) and
|
|
# .github/workflows/ci.yml (GitHub Actions, production) implement.
|
|
#
|
|
# Runs the same three stages in the same order:
|
|
# 1. lint — py_compile all Python files
|
|
# 2. test — pytest test suite (offline)
|
|
# 3. check-only — run_platform.sh --check-only (offline, no AWS)
|
|
#
|
|
# Fails on the first stage that errors. Exits 0 with "CI PIPELINE OK"
|
|
# when all stages pass.
|
|
#
|
|
# Usage:
|
|
# bash scripts/run_ci.sh # run all stages
|
|
# bash scripts/run_ci.sh --quiet # suppress per-stage banners
|
|
set -euo pipefail
|
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
cd "$ROOT"
|
|
|
|
QUIET=0
|
|
for arg in "$@"; do
|
|
case "$arg" in
|
|
--quiet) QUIET=1 ;;
|
|
*) echo "FAIL: unknown argument: $arg" >&2; exit 1 ;;
|
|
esac
|
|
done
|
|
|
|
banner() {
|
|
[ "$QUIET" = "1" ] || echo ""
|
|
echo "── $1 ──"
|
|
[ "$QUIET" = "1" ] || echo ""
|
|
}
|
|
|
|
fail() { echo "FAIL: $*" >&2; exit 1; }
|
|
|
|
echo "=== ACDL CI Pipeline (local reproduction) ==="
|
|
echo "contract: pipelines/ci.yaml (3 stages)"
|
|
echo ""
|
|
|
|
banner "Stage 1/3: lint (py_compile)"
|
|
python3 -m py_compile \
|
|
core/confidence_signal.py \
|
|
core/outbox_writer.py \
|
|
core/contract_resolver.py \
|
|
core/lambda/contract_ingestor.py \
|
|
adapters/terraform/adapter.py \
|
|
adapters/terraform/policy/checkov_adapter.py \
|
|
adapters/terraform/policy/custom_rules/acdl_tagging.py \
|
|
adapters/wiz/wiz_adapter.py \
|
|
adapters/kyverno/kyverno_adapter.py \
|
|
scripts/push_consumer_image.py \
|
|
|| fail "lint: py_compile failed"
|
|
echo "lint: OK"
|
|
|
|
banner "Stage 2/3: test (pytest)"
|
|
python3 -m pytest tests/ -v --tb=short || fail "test: pytest failed"
|
|
echo "test: OK"
|
|
|
|
banner "Stage 3/3: check-only (run_platform.sh --check-only)"
|
|
bash scripts/run_platform.sh --check-only || fail "check-only: run_platform.sh failed"
|
|
echo "check-only: OK"
|
|
|
|
echo ""
|
|
echo "=== CI PIPELINE OK ==="
|
|
echo "3 stages passed: lint, test, check-only"
|
|
exit 0 |