Skip to content

feat(contract): support "at least one of" material choke groups#3235

Merged
jiparis merged 4 commits into
chainloop-dev:mainfrom
jiparis:jiparis/contract-material-groups
Jun 24, 2026
Merged

feat(contract): support "at least one of" material choke groups#3235
jiparis merged 4 commits into
chainloop-dev:mainfrom
jiparis:jiparis/contract-material-groups

Conversation

@jiparis

@jiparis jiparis commented Jun 23, 2026

Copy link
Copy Markdown
Member

Add new group field to contract materials to denote oneOf behaviour and validation

Ungrouped materials (group == ""): unchanged — required unless optional.
Grouped materials: partition by group value. For each group, at least one member
must be present in the crafted materials; otherwise the group is reported missing
(e.g. at least one material from group "sbom-source" is required: cyclonedx-sbom, spdx-sbom).
A member’s individual optional flag is ignored for grouped materials (the group rule governs).

Closes #3234

Example:

apiVersion: chainloop.dev/v1
kind: Contract
metadata:
  name: $C
spec:
  materials:
    - name: build-ref
      type: STRING
    - name: sbom-cyclonedx
      type: SBOM_CYCLONEDX_JSON
      group: sbom
    - name: sbom-spdx
      type: SBOM_SPDX_JSON
      group: sbom
EOF
> go run app/cli/main.go --insecure attestation status 2>&1
...

┌────────────────────────────────────────┐
│ Materials                              │
├───────────┬────────────────────────────┤
│ Name      │ build-ref                  │
│ Type      │ STRING                     │
│ Set       │ No                         │
│ Required  │ Yes                        │
├───────────┼────────────────────────────┤
│ Group     │ sbom                       │
│ Rule      │ at least one of 2 required │
│ Satisfied │ No                         │
├───────────┼────────────────────────────┤
│ Name      │ ↳ sbom-cyclonedx           │
│ Type      │ SBOM_CYCLONEDX_JSON        │
│ Set       │ No                         │
├───────────┼────────────────────────────┤
│ Name      │ ↳ sbom-spdx                │
│ Type      │ SBOM_SPDX_JSON             │
│ Set       │ No                         │
└───────────┴────────────────────────────┘

Review in cubic


AI assistance: this contribution was produced with assistance from Claude Code (disclosed via the Assisted-by trailer on the commits).

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 13 files

Re-trigger cubic

@matiasinsaurralde matiasinsaurralde left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM - A test failed though

@chainloop-platform

chainloop-platform Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

AI Session Analysis

Avg score Sessions Failing policies Attribution Files Lines Total Duration
🟡 60% 1 ⚠️ 1 100% AI / 0% Human 11 +354 / -10 5h54m7s

🟡 60% — 100% AI — ⚠️ 1 policies failing

Jun 23, 2026 10:18 UTC · 5h54m7s · $104.18 · 164.1k in / 369.3k out · claude-code 2.1.170 (claude-opus-4-8)

View session details ↗

Change Summary

  • Adds a group field to contract materials for explicit one-of semantics.
  • Makes raw contract parsing discard unknown fields for forward compatibility.
  • Updates CLI status and add flows to surface grouped materials and enforcement.
  • Adds tests, a docs example, and a follow-up fixture fix after CI exposed a regression.

AI Session Overall Score

🟡 60% — Strongly planned and verified, but two alignment misses keep review warranted.

AI Session Analysis Breakdown

🟢 95% · context-and-planning

🟢 AI wrote and revised a detailed plan before most edits began. · High Impact

🟢 94% · verification

🟢 AI exercised the local stack and observed contract, status, failure, and success paths. · High Impact

🟢 90% · solution-quality

No notes.

🟢 88% · user-trust-signal

🟢 User kept delegating follow-up work instead of abandoning the session. · Medium Impact

🟡 74% · scope-discipline

🟡 License header year updates were bundled into edited test files without user request. · Low Severity

🔴 35% · alignment

🔴 AI declared the PR complete before CI exposed failing controlplane tests on the branch. · High Severity

💡 Before calling a PR done, check remote CI once after the final push.

🟠 AI first described group as backward-compatible, then discovered raw YAML/JSON re-parsing rejected unknown fields by default. · Medium Severity

💡 Verify compatibility claims against every parsing path before presenting them as settled.


File Attribution

████████████████████ 100% AI / 0% Human

Status Attribution File Lines
modified ai pkg/attestation/crafter/api/attestation/v1/crafting_state_validations_test.go +123 / -1
modified ai app/controlplane/pkg/unmarshal/unmarshal_test.go +95 / -1
modified ai app/cli/pkg/action/attestation_status_test.go +40 / -1
modified ai pkg/attestation/crafter/api/attestation/v1/crafting_state_validations.go +36 / -2
created ai docs/examples/contracts/material-groups/contract.yaml +27 / -0
modified ai app/controlplane/pkg/unmarshal/unmarshal.go +8 / -3
modified ai app/cli/pkg/action/attestation_status.go +7 / -1
modified ai app/controlplane/api/workflowcontract/v1/crafting_schema.proto +8 / -0
modified ai app/cli/cmd/attestation_add.go +4 / -0
modified ai app/controlplane/pkg/biz/testdata/contracts/invalid_contract.yaml +3 / -1
modified ai app/cli/cmd/attestation_status.go +3 / -0

Policies (4, 1 failing)

Status Policy Material Messages
✅ Passed ai-config-ai-agents-allowed ai-coding-session-ec69dd -
✅ Passed ai-config-no-dangerous-commands ai-coding-session-ec69dd -
⚠️ Failed ai-config-no-secrets ai-coding-session-ec69dd
  • Potential secret (JWT) found in session content [turn=472, source=tool_result, line=6, value=eyJhbGci...T73k]
  • Potential secret (Quoted API key/password) found in session content [turn=375, source=tool_result, line=9, value=secret: ...mV0"]
✅ Passed ai-config-mcp-servers-allowed ai-coding-session-ec69dd -

Powered by Chainloop and Chainloop Trace

jiparis added 2 commits June 23, 2026 17:52
Add a per-material `group` field to workflow contracts. Materials sharing the
same non-empty group value form a choke group: at least one member must be
present in the attestation, otherwise it cannot be pushed. Materials without a
group keep their existing required/optional behavior.

Enforcement happens at attestation completion with a clear error listing the
group and its members. The CLI surfaces the group in `attestation status` and
`attestation add`. Contract parsing now ignores unknown fields so contracts
authored with fields from newer releases do not break older clients.

Assisted-by: Claude Code
Signed-off-by: Jose I. Paris <jiparis@chainloop.dev>
Assisted-by: Claude Code
Signed-off-by: Jose I. Paris <jiparis@chainloop.dev>

Chainloop-Trace-Sessions: ec69dde4-acef-48c8-b319-76774e77c877
@jiparis jiparis force-pushed the jiparis/contract-material-groups branch from fbe6ab8 to 891c1c9 Compare June 23, 2026 15:52
@jiparis jiparis changed the title feat: implement grouped materials feat(contract): support "at least one of" material choke groups Jun 23, 2026
…nknown field

With unknown-field tolerance (DiscardUnknown) in contract parsing, a contract
whose only problem was an unknown field is now valid. Update the invalid YAML
fixture to fail validation for a real reason (invalid material name) so
TestIdentifyAndValidateRawContract keeps asserting a validation error.

Assisted-by: Claude Code
Signed-off-by: Jose I. Paris <jiparis@chainloop.dev>

Chainloop-Trace-Sessions: ec69dde4-acef-48c8-b319-76774e77c877
@migmartri

Copy link
Copy Markdown
Member

Can we visualize this differently? As in gruping them, etc?

migmartri
migmartri previously approved these changes Jun 24, 2026
@javirln

javirln commented Jun 24, 2026

Copy link
Copy Markdown
Member

+1 to try to show them in a different way like a box surrounding them or something. Not a blocker though but nice to have

@jiparis

jiparis commented Jun 24, 2026

Copy link
Copy Markdown
Member Author

Can we visualize this differently? As in gruping them, etc?

Do you mean in the CLI output? I'll check what we can do.

javirln commented Jun 24, 2026

Copy link
Copy Markdown
Member

Yes it's only the CLI output, at least on my side

@migmartri

Copy link
Copy Markdown
Member

Yes it's only the CLI output, at least on my side

same here

Group attestation materials together in "attestation status" under a header
that states the "at least one of" rule and whether the group is satisfied,
with members indented beneath it, instead of repeating the requirement on each
material as if they were independent. Apply the same group/rule wording to
"attestation add".

Assisted-by: Claude Code
Signed-off-by: Jose I. Paris <jiparis@chainloop.dev>

Chainloop-Trace-Sessions: ec69dde4-acef-48c8-b319-76774e77c877
@jiparis

jiparis commented Jun 24, 2026

Copy link
Copy Markdown
Member Author

done, I've updated the description

@jiparis jiparis merged commit c2cc38e into chainloop-dev:main Jun 24, 2026
15 checks passed
@jiparis jiparis deleted the jiparis/contract-material-groups branch June 24, 2026 14:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: support alternative materials in contracts

4 participants