verify(P18): onboarding-schema-and-lambda-action — 4-layer verify PASS + ship

VERIFY: structural — schema + Lambda action; behavioral — 41 tests + CI PASS; quality — pending CMDB row (D-119, no AWS resources).

---ci---
project: acdl
phase: 18
milestone: v1.16
status: complete
phase_role: execution
requirements:
  covered: [REQ-182]
  partial: []
---/ci---
This commit is contained in:
Jon Chery
2026-08-01 13:24:58 +00:00
parent e8effef415
commit c19a5d66f2
3 changed files with 149 additions and 1 deletions
+61
View File
@@ -398,6 +398,65 @@ def _validate_change_request(payload):
}
def _onboard_consumer(payload):
"""P18 (REQ-182): accept a self-service onboarding request.
Validates the payload against schemas/onboarding.schema.json, then
writes a 'pending' row to nova-contracts (D-119). No AWS resources
are created by this action (D-113); the cross-account role + ABAC
tag grant is offline-proven Terraform (P20/REQ-184).
"""
import jsonschema
schema_path = os.path.join(os.path.dirname(os.path.dirname(
os.path.dirname(os.path.abspath(__file__)))),
"schemas", "onboarding.schema.json")
try:
with open(schema_path) as f:
schema = json.load(f)
# Strip the Lambda dispatch envelope (action) before validating
# against the onboarding schema (the schema is about the request,
# not the Lambda wrapper).
onboarding_payload = {k: v for k, v in payload.items() if k != "action"}
jsonschema.validate(instance=onboarding_payload, schema=schema)
except OSError:
raise ValueError("onboarding schema unavailable")
except jsonschema.ValidationError as e:
raise ValueError(f"onboarding payload invalid: {e.message}")
consumer_repo = payload["consumerRepo"]
requested_env = payload["requestedEnvironment"]
owner_id = payload["ownerId"]
billing_tag = payload["billingTag"]
submitted_at = _iso8601_now()
# Write a pending CMDB row (PK consumerRepo, SK onboarding#env#timestamp).
table = _get_dynamodb().Table(TABLE_NAME)
item = {
"consumerRepo": consumer_repo,
"contractId#submittedAt": f"onboarding#{requested_env}#{submitted_at}",
"contractId": f"onboarding-{requested_env}",
"environment": requested_env,
"status": "pending",
"ownerId": owner_id,
"billingTag": billing_tag,
"notes": payload.get("notes", ""),
"submittedAt": submitted_at,
}
table.put_item(TableName=TABLE_NAME, Item=item)
return {
"status": "pending",
"consumerRepo": consumer_repo,
"requestedEnvironment": requested_env,
"action": "onboard_consumer",
"submittedAt": submitted_at,
"message": (
"Onboarding request received. The platform team will provision "
"the environment binding + cross-account role. Track the status "
"via the nova-contracts table (status=pending → granted)."
),
}
def lambda_handler(event, context):
"""AWS Lambda handler entry point.
@@ -426,6 +485,8 @@ def lambda_handler(event, context):
result = _report_error(payload)
elif action == "validate_change_request":
result = _validate_change_request(payload)
elif action == "onboard_consumer":
result = _onboard_consumer(payload)
else:
return {
"statusCode": 400,