Conversation
Reviewer's GuideAdds a new Architecture Decision Record (ADR) describing the planned integration of Enterprise Contract (Conforma) into Trustify, including architecture, data model, APIs, implementation phases, and open questions. Sequence diagram for SBOM validation with Enterprise ContractsequenceDiagram
actor User
participant WebUI
participant ApiGateway
participant EcEndpoints
participant EcService
participant PolicyManager
participant ConformaExecutor
participant ConformaCli
participant ResultParser
participant ResultPersistence
participant Postgres
participant S3Storage
User->>WebUI: Open_SBOM_details
User->>WebUI: Click_Validate_with_EC
WebUI->>ApiGateway: POST_/api_v2_sboms_{id}_ec-validate
ApiGateway->>EcEndpoints: handle_validate_request(sbomId, policyId)
EcEndpoints->>EcService: validate_sbom(sbomId, policyId)
EcService->>PolicyManager: get_policy_config(policyId)
PolicyManager-->>EcService: EcPolicy
EcService->>ConformaExecutor: request_validation(sbomId, EcPolicy)
ConformaExecutor->>ConformaCli: spawn_process(sbomPath, policyRef, configuration)
ConformaCli-->>ConformaExecutor: exit_code_stdout_stderr
ConformaExecutor-->>EcService: raw_output_exit_code
EcService->>ResultParser: parse_output(raw_output)
ResultParser-->>EcService: EcValidationResult
EcService->>ResultPersistence: save_results(EcValidationResult)
ResultPersistence->>Postgres: INSERT_ec_validation_results
EcService->>S3Storage: store_ec_report(reportContent)
S3Storage-->>EcService: report_url
EcService-->>EcEndpoints: EcValidationResult_with_report_url
EcEndpoints-->>ApiGateway: HTTP_200_validation_result
ApiGateway-->>WebUI: JSON_validation_result
WebUI-->>User: Show_status_badge_and_violations
note over EcService,ConformaExecutor: On_error_or_timeout_status_error_is_saved_and_returned
Entity relationship diagram for EC policy and validation result tableserDiagram
SBOM {
UUID id PK
STRING name
TIMESTAMP created_at
}
EcPolicies {
UUID id PK
STRING name
TEXT description
STRING policy_ref
STRING policy_type
JSONB configuration
TIMESTAMP created_at
TIMESTAMP updated_at
}
EcValidationResults {
UUID id PK
UUID sbom_id FK
UUID policy_id FK
STRING status
JSONB violations
JSONB summary
STRING report_url
TIMESTAMP executed_at
INTEGER execution_duration_ms
STRING conforma_version
TEXT error_message
}
SBOM ||--o{ EcValidationResults : has
EcPolicies ||--o{ EcValidationResults : used_by
Class diagram for EC validation backend module structureclassDiagram
class EcService {
+validateSbom(sbomId: Uuid, policyId: Uuid) EcValidationResult
+getLatestReport(sbomId: Uuid) EcValidationResult
+getReportHistory(sbomId: Uuid) Vec~EcValidationResult~
}
class PolicyManager {
+getPolicyConfig(policyId: Uuid) EcPolicy
+validatePolicyRef(policyRef: String) bool
+listPolicies() Vec~EcPolicy~
}
class ConformaExecutor {
+requestValidation(sbomPath: String, policy: EcPolicy, timeoutMs: u64) ConformaRawResult
+checkHealth() bool
}
class ResultParser {
+parseOutput(rawJson: String, exitCode: i32) EcValidationResult
}
class ResultPersistence {
+saveResults(result: EcValidationResult) EcValidationResult
+getLatestForSbom(sbomId: Uuid) EcValidationResult
+getHistoryForSbom(sbomId: Uuid) Vec~EcValidationResult~
}
class EcPolicy {
+id: Uuid
+name: String
+description: String
+policyRef: String
+policyType: String
+configuration: JsonValue
+createdAt: DateTime
+updatedAt: DateTime
}
class EcValidationResult {
+id: Uuid
+sbomId: Uuid
+policyId: Uuid
+status: String
+violations: JsonValue
+summary: JsonValue
+reportUrl: String
+executedAt: DateTime
+executionDurationMs: i64
+conformaVersion: String
+errorMessage: String
}
class ConformaRawResult {
+stdout: String
+stderr: String
+exitCode: i32
+durationMs: i64
}
class EcError {
+message: String
+code: String
}
EcService --> PolicyManager : uses
EcService --> ConformaExecutor : uses
EcService --> ResultParser : uses
EcService --> ResultPersistence : uses
ResultPersistence --> EcValidationResult : persists
PolicyManager --> EcPolicy : manages
ConformaExecutor --> ConformaRawResult : returns
EcService --> EcError : returns_on_failure
ResultParser --> EcError : may_return
ConformaExecutor --> EcError : may_return
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've found 5 issues, and left some high level feedback:
- In the C4Context mermaid diagram, the
Rel(trustify, s3, "I3s", S3/Minio Storager, trustify, ...)line looks malformed (extra parameters, typo in label), which will likely break rendering—please correct the relation syntax and labels. - In the component diagram, the route definition
GET /sbms/{id}/ec-reportappears to be a typo and should probably beGET /sboms/{id}/ec-reportto stay consistent with the rest of the API design. - There are a few small wording/typo issues that could be cleaned up for clarity, e.g.,
policy selectreference management UIin the frontend tasks list and duplicated 'Policy delete confirmation' bullet, which might confuse future readers of the ADR.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In the C4Context mermaid diagram, the `Rel(trustify, s3, "I3s", S3/Minio Storager, trustify, ...)` line looks malformed (extra parameters, typo in label), which will likely break rendering—please correct the relation syntax and labels.
- In the component diagram, the route definition `GET /sbms/{id}/ec-report` appears to be a typo and should probably be `GET /sboms/{id}/ec-report` to stay consistent with the rest of the API design.
- There are a few small wording/typo issues that could be cleaned up for clarity, e.g., `policy selectreference management UI` in the frontend tasks list and duplicated 'Policy delete confirmation' bullet, which might confuse future readers of the ADR.
## Individual Comments
### Comment 1
<location> `docs/adrs/00012-enterprise-contract-integration.md:82` </location>
<code_context>
+ Rel(user, trustify, "Request Compliance<br/>View compliance status", "API/GUI")
+ Rel(trustify, conforma, "Executes policy validation", "Spawn Process")
+ Rel(conforma, policyRepo, "Fetches policies", "Git/HTTPS")
+ Rel(trustify, s3, "I3s", S3/Minio Storager, trustify, $offsetX="-30", $offsetY="+20")
+
+ UpdateRelStyle(trustify, conforma, $offsetX="-40")
</code_context>
<issue_to_address>
**issue (typo):** Fix typos in the S3 relationship label and description ("I3s" and "Storager").
"I3s" should be "S3", and "S3/Minio Storager" should be updated to something like "S3/Minio Storage" to keep the diagram text clear and avoid confusion.
```suggestion
Rel(trustify, s3, "S3", "S3/Minio Storage", trustify, $offsetX="-30", $offsetY="+20")
```
</issue_to_address>
### Comment 2
<location> `docs/adrs/00012-enterprise-contract-integration.md:105` </location>
<code_context>
+ ContainerDb(postgres, "PostgreSQL", "DBMS", "Stores SBOM metadata, relationships, <br/>and EC validation results")
+ Container(ecModule, "EC Validation Module", "Rust", "Orchestrates Conforma CLI<br/>execution and result persistence")
+ ContainerDb(s3, "Object Storage", "S3/Minio", "Stores SBOM documents and EC reports")
+ Container(storage, "Storage Service", "Rust", "Manages document storage<br/>(SBOMs, policies results)")
+ }
+
</code_context>
<issue_to_address>
**suggestion (typo):** Clarify the phrase "policies results" in the storage service description.
"Policies results" reads awkwardly. Consider "policy results" or "policies and results" for clarity.
```suggestion
Container(storage, "Storage Service", "Rust", "Manages document storage<br/>(SBOMs, policy results)")
```
</issue_to_address>
### Comment 3
<location> `docs/adrs/00012-enterprise-contract-integration.md:160` </location>
<code_context>
+ }
+
+
+ Rel(api, ecEndpoints, "POST /sboms/{id}/ec-validate,<br/>GET /sbms/{id}/ec-report", "JSON/HTTPS")
+ Rel(ecEndpoints, ecService, "validate_sbom()<br/> get_ec_report()", "Function call")
+ Rel(ecService, policyManager, "get_policy_config()", "Function call")
</code_context>
<issue_to_address>
**issue (typo):** Fix the likely typo in the path `GET /sbms/{id}/ec-report`.
This relation string uses `/sbms/{id}/ec-report` while the rest of the API uses `/sboms/`. Please update this to `/sboms/{id}/ec-report` to match the documented endpoint.
```suggestion
Rel(api, ecEndpoints, "POST /sboms/{id}/ec-validate,<br/>GET /sboms/{id}/ec-report", "JSON/HTTPS")
```
</issue_to_address>
### Comment 4
<location> `docs/adrs/00012-enterprise-contract-integration.md:355` </location>
<code_context>
+3. **Flexibility**: Support multiple policy configurations for different requirements
+4. **Integration Ready**: REST API enables integration with CI/CD pipelines
+5. **Scalability**: Async execution prevents blocking on long-running validations
+6. **Extensibility**: Module design allows future enhancement (webhooks, notifications, etc.)
+7. **Open Source**: Conforma is open-source and actively maintained
+
</code_context>
<issue_to_address>
**nitpick (typo):** Use the plural "enhancements" instead of "enhancement".
Because you list multiple examples in parentheses, use "future enhancements" rather than "future enhancement" for correct grammatical agreement.
```suggestion
6. **Extensibility**: Module design allows future enhancements (webhooks, notifications, etc.)
```
</issue_to_address>
### Comment 5
<location> `docs/adrs/00012-enterprise-contract-integration.md:462-464` </location>
<code_context>
+- [ ] Implement validation results display with summary statistics
+- [ ] Build violations list component with expandable details
+- [ ] Create validation history timeline view
+- [ ] Add policy selectreference management UI (admin pages)
+ - [ ] Policy reference list view with search/filter (shows name, external URL, type)
+ - [ ] Policy reference create/edit form (Git URL, OCI ref, auth config)
</code_context>
<issue_to_address>
**issue (typo):** Fix the typo "selectreference" in the frontend tasks checklist.
Consider rephrasing to something like “Add policy reference management UI (admin pages)” for clarity.
```suggestion
- [ ] Create validation history timeline view
- [ ] Add policy reference management UI (admin pages)
- [ ] Policy reference list view with search/filter (shows name, external URL, type)
```
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
d8a3b05 to
06ef31a
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #2227 +/- ##
==========================================
+ Coverage 70.41% 70.43% +0.01%
==========================================
Files 413 413
Lines 23874 23874
Branches 23874 23874
==========================================
+ Hits 16812 16816 +4
+ Misses 6152 6141 -11
- Partials 910 917 +7 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
f9f50d5 to
04a07fe
Compare
|
@gildub Just checking, the title says "WIP". Can we turn this into a draft PR? Or is it ready to be reviewed? So we can drop the WIP. |
ctron
left a comment
There was a problem hiding this comment.
Thanks for the PR. A few observations:
- The ADR feels quite verbose but I'm missing detailed information. I think it would be good to remove the obvious or not really relevant bits and provide more detail to the important parts. Keeping a focus on the tricky bits.
- Reading through the ADR, it seems to touch the same/similar topics several times. But with different idea/outcomes/definitions. That feels confusing. I think topics like "database", "conforma API", etc should be discussed in a consistent section.
I still have some technical questions:
- I'm still not sure what triggers the validation of an SBOM. To my understanding, the validation is not triggered until a user specifically asks for it? If that's the case, that doesn't fit the idea in the ADR of making things more automatic ("Automatically validate SBOMs against organizational policies"). Why can this be requested during the upload? Or all documents automatically get validated against some set of policies?
- Why don't we re-use the existing document storage system? What data would we store anyway (as a BLOB) and what's the format of that document?
- How do we scale this? How do we handle situations where multiple users ask for validations at the same time?
- What happens when a user requests the same validation for the same SBOM again?
- What's the definition of the Conforma API (even if it's a CLI).
- Why can we put this behind a thin HTTP API wrapper, which might solve the scaling issue on k8s
- What's the structure of the JSON fields we store and the data we exchange over the API?
- How do we handle long-running requests? We already know that the UI will time out after a minute or two. If that's a problem, we should provide a mechanism to deal with this right away.
|
|
||
| ## Status | ||
|
|
||
| PROPOSED |
There was a problem hiding this comment.
This should be "approved", because it would be once it's merged.
04a07fe to
6b70a46
Compare
|
Thank you for the review, I'll reduce some redundancy in the document.
Sorry for any confusion around the storage system which is described as external because AWS or Minio objects are managed by Trustify but independent systems per say.
The validation being an async process, once a validation is in progress it's flagged as such and any new request will refer to the initial one.
Because we store the results of the already requested validations we don't have to re-execute them.
We expressed with Conforma team our need for an API. My short answer is yes but will take time.
In the meantime Conforma API is available the only approach for now is to interface to Conforma through it's CL tool because it's not designed as a library which won't be a solution either for a Go wrapper.
Among the various format offered by Conforma CL we obviously will request the JSON format. The details will be added to the document.
The request should be async and therefore not blocking for the UI. Once a validation has been issued, the SBOM's policy validation will be flagged as "In Progress" or equivalent. |
4794489 to
920340b
Compare
👍
👍 Then we should update the ADR to reflect this.
Well, we do have
That's good. The ADR should describe how that works. Also in the DB tables, etc.
Perfect, I'd love to see that described in the ADR.
Right, and this ADR should describe that. In a single spot in the document. Ideally, describe the HTTP wrapper around that.
I understand that, but we could wrap it with an HTTP server, outside of the trustify process.
👍
Perfect, the ADR should describe in detail how that process works. |
388ce8d to
9883b36
Compare
b843449 to
3c94232
Compare
ctron
left a comment
There was a problem hiding this comment.
Thanks for the work on the ADR.
- A lot of comments just have been resolved, but not worked on. I can't link all of them. They are still valid. (e.g. table names, type column, …)
- Some comments are still open and need to be worked on.
- The main issue I still see is the strategy of running the conforma CLI directly from the trustd binary. This should be isolated into its own process. Otherwise we will cause ourselves a lot of troubles.
|
|
||
| ### The Data Model | ||
|
|
||
| **`ec_policies`** - Stores references to external policies, not the policies themselves |
There was a problem hiding this comment.
This is still plural. We do use singular naming tables.
There was a problem hiding this comment.
Thanks, I've now verified the entire document !
|
|
||
| #### Conforma CLI Execution | ||
|
|
||
| Conforma is invoked via tokio::process::Command to avoid blocking the async runtime. All arguments are passed as an array — never as a shell string — to prevent CLI injection. Execution has a configurable timeout (default 5 minutes); large SBOMs are streamed to a temp file and passed by path rather than piped via stdin, which avoids OOM issues with the parent process. |
There was a problem hiding this comment.
It looks like this comment got lost somehow. I didn't see it addresses. See: #2227 (comment)
I still think that this approach is not a good approach and we should wrap conforma into an HTTP endpoint. And only call that endpoint.
There was a problem hiding this comment.
Let me clarify an important detail, the "Conforma Executer" component is already a detached service wrapping Conforma CLI in the sense it's interfacing (via spawned execution) with it.
Please develop why "this approach is not a good approach" and please explain what do you mean by wrapping conforma using an HTTP endpoint. How would that be different from the current components solution with "EC Endpoints", the "EC Service" and the "Conforma Executer" ?
The main reason against an HTTP wrapper is that Conforma doesn't have an API and is only a CLI program for now.
| - Version compatibility | ||
| - Document required Conforma version; validate on startup | ||
| - Concurrent load exhausting resources | ||
| - Semaphore (default: 5) |
There was a problem hiding this comment.
This won't work, as it's not know how many resources a conforma process uses. Running this in the same pod as trustd is a mistake. One pod should ideally run one process. Conforma may cause an OOM situation, which would result in trustify being unavailable as well.
There was a problem hiding this comment.
You're right and when running in a cluster environment Conforma should effectively be running in a separate pod. Alternatively when running in a standalone deployment then it would require to have Conforma to be installed separately.
I'll update the ADR once we clarify the aproach.
|
|
||
| #### Concurrency and Backpressure | ||
|
|
||
| Concurrent Conforma processes are bounded by a semaphore (default: 5). When the semaphore is exhausted, incoming validation requests return 429 Too Many Requests immediately rather than queuing or blocking indefinitely. This makes the capacity limit explicit to callers (e.g. CI pipelines can implement their own retry with backoff). If demand grows to warrant it, a proper queue (Redis/RabbitMQ) is the deferred alternative considered below. |
There was a problem hiding this comment.
This will also not work properly if we have multiple pods running.
There was a problem hiding this comment.
@ctron, please clarify your concerns.
From you last comment, it becomes clearer Conforma should be deployed separately from Trustify. Conforma just need to be accessible to Trustify.
|
|
||
| #### Data Retention | ||
|
|
||
| Validation results accumulate over time. A retention policy (default: 90 days, configurable) should be implemented to prune old ec_validation_results rows and their corresponding S3 reports. This is deferred to the implementation phase but must be included before production rollout. |
There was a problem hiding this comment.
If that should be implemented, it should be outlined "how".
There was a problem hiding this comment.
@ctron, this is a suggestion that came from an earlier version. Meanwhile there are no such requirement, therefore I've removed it.
|
|
||
| ### Deferred Validation | ||
|
|
||
| I has been decided that uploaded SBOMs start in "Pending" status and are not discoverable until validated. |
There was a problem hiding this comment.
The required changes for this should be described in this ADR.
4efda2d to
66cfa31
Compare
|
@ctron, I've replaced the former "Conforma Executor" component with an external "HTTP API" EC wrapper. Trustify "EC Service" will make REST requests for policies validation (the HTTP API side) and the wrapper will in turn trigger Conform CLI via a system spawn as we have confirmation Conforma is only pure CLI without any library interaction possibilities. |
40e8244 to
f004ba6
Compare
|
regarding #2227 (review),
Sorry for any confusion it's to say it needs to use a storage system to store validation output (JSON).
The initial state of the rule validation of a given SBOM is "Pending" since it's not done at upload time for now.
Yes that's a better idea and we've acknowledge to use such approach.
The JSON structure is now available in the document through an example generated from Conforma CLI
The "EC service" module will trigger the HTTP wrapper by API which will provide and ID. |
ctron
left a comment
There was a problem hiding this comment.
It's heading in the right direction. A lot of comments still need to be resolves. Many of the had already been opened in a previous review but I didn't see them processed.
A few questions I still need to understand:
- How is security handled between the trustify and the conforma HTTP endpoint? And the other way round?
- what is the API of the HTTP endpoint wrapper?
- what is the API for the callback? How is security handled?
| - `configuration` (JSONB) - Branch, tag, auth credentials, etc. | ||
| - `created_at`, `updated_at` (TIMESTAMP) | ||
|
|
||
| **`ec_validation_results`** - one row per validation execution |
There was a problem hiding this comment.
Please also make this singular, like the other.
| - **Fail** — Conforma validation found policy violations; violation details are linked. | ||
| - **Error** — an execution error occurred (CLI crash, policy fetch failure, timeout). The error is surfaced separately, and the validation can be re-triggered. | ||
|
|
||
| The "In Progress" state serves as a concurrency guard: if a validation is already running for a given SBOM + policy pair, subsequent requests are rejected (409 Conflict), preventing duplicate work. |
There was a problem hiding this comment.
If that's the case, then I think it is import to describe how we handle the concurrency (considering the database) and failures running the validation. For example:
- A user requests the validation
- The entry is marked as "In progress", but the validation didn't start (due to some issues).
How would the entry be recovered from that state? There are other cases, we should document how that would work.
There was a problem hiding this comment.
@ctron, the HTTP Wrapper returns a validation id which is then stored in database against the related SBOM.
This id is used later on, to provide the validation result.
If the validation fails, then the validation need to be reset to "Pending".
There was a problem hiding this comment.
If the validation fails, then the validation need to be reset to "Pending".
Who is in charge of this? What happens when the validation pod just crashes (or gets OOM killed)?
There was a problem hiding this comment.
Yes, this must be effectively taken care of and we need to discuss how.
As the HTTP Wrapper is an external systems (pods or standalone), Trustify cannot orchestrate them.
So a status indicating if HTTP wrapper is alive would inform the user.
There was a problem hiding this comment.
I was wondering about this part:
If the validation fails, then the validation need to be reset to "Pending".
"needs to be", but who would do that. How does this work?
There was a problem hiding this comment.
Effectively another state variable is needed to support the validation process and not be mixed up with the validation results.
I've added
ec_status (ENUM) - 'queued', 'in_progress', 'completed', 'failed'
An SBOM's validation state won't be updated unless the ec_status has 'completed'.
|
|
||
| Each SBOM + policy pair has a validation state that follows this lifecycle: | ||
|
|
||
| - **Pending** — initial state, set when an SBOM is associated with a policy (e.g., a default policy assigned at SBOM upload time; upload itself is outside the scope of this ADR). Indicates no validation has been triggered yet for this SBOM against this policy. |
There was a problem hiding this comment.
A few lines up, it says "Validation on upload is deferred to a follow-up version.", here we have "a default policy assigned at SBOM upload time; upload itself is outside the scope of this ADR". This seems confusing. If we are designing this, we should. Unless it's out of scope, then that maybe may end up in some "future work" section. In general, if we describe such a state machine, we probably need this though.
There was a problem hiding this comment.
@ctron , I'm not sure what you mean,
My initial understanding was that if a Policy is defined along a SBOM then validation could be triggered.
Now if a default Policy is defined globally on Trustify then the latter could be used if no policy is attached to an SBOM.
There was a problem hiding this comment.
I'm not aware of any default policy. Does this ADR describe something like this?
If so, then maybe I would again suggest do have those ideas before the "decision" section. Maybe it's just an ordering issue.
There was a problem hiding this comment.
@ctron, PM confirmed a default Policy define across the application would be used.
That clears up the need for a Policy to be attached to an SBOM to be validated as the default global" one can be used.
In the case a Policy is attached to a SBOM then that one would be used for validation.
| What is stored where | ||
|
|
||
| - PostgreSQL: validation status, structured violations (JSONB), summary statistics, foreign keys to SBOM and policy. Indexed on sbom_id, status, executed_at. | ||
| - S3/Minio: full raw Conforma JSON report, linked from the DB row via report_url. Keeps DB rows small while preserving audit completeness. |
There was a problem hiding this comment.
I think I already wrote that. We do have a storage system for documents. report_url is not part of this. In my opinion, this must be aligned with the current architecture. Otherwise we are re-creating stuff that we already have.
If there is a good reason why we do that, then we should document that reason.
There was a problem hiding this comment.
@ctron, yes the idea is use existing storage to store full original JSON validation report. I'm not sure what in those lines makes you think otherwise.
There was a problem hiding this comment.
S3/Minio
The storage system uses S3 (compatible) stores, or file system. Having "S3/Minio" here, seems to indicate to me that the responsiblity is with S3. Not with the storage system. Also, I didn't see any relationships to the source_document table before.
linked from the DB row via report_url
Not sure how that works with the storage? What does the URL refer to? Maybe an example helps.
There was a problem hiding this comment.
@ctron, my apologies as I wasn't using the right terminology, let me replace S3/Minio with storage (as file system or S3 equiv.) and update the ADR accordingly.
The URL was the path or name of the object in the storage system, I replaced it with report_path.
|
|
||
| ## Consequences | ||
|
|
||
| Using an EC Wrapper decouples the validation process into an external service. This better caters for large-scale deployments as EC validation has its own resource constraints. Meanwhile it adds infrastructure complexity as the EC Wrapper must be deployed and maintained alongside the Conforma CLI. |
There was a problem hiding this comment.
I would see the "deployment" as a pod, running a container, which has the HTTP wrapper as well as the conforma CLI.
Maybe this needs to be fleshed out a bit.
|
|
||
| #### Policy Management | ||
|
|
||
| ec_policies stores external references only. Conforma fetches the actual policy at validation time, which means Trustify does not cache policy content by default. The trade-off: validation always uses the latest policy version, but network failures or policy repo outages will cause execution errors. For private policy repositories, authentication credentials are stored in the configuration JSONB column and must be encrypted at rest; they are never logged. |
There was a problem hiding this comment.
I think I don't fully understand it. Above I read that trustify will delete cached policies. Here trustify does not cache content. If content is cached, wouldn't that then leads to stale policies? Wouldn't it make sense to have some TTL setting? What happens if one pod has a different version than others?
| #### Policy Management | ||
|
|
||
| ec_policies stores external references only. Conforma fetches the actual policy at validation time, which means Trustify does not cache policy content by default. The trade-off: validation always uses the latest policy version, but network failures or policy repo outages will cause execution errors. For private policy repositories, authentication credentials are stored in the configuration JSONB column and must be encrypted at rest; they are never logged. | ||
|
|
There was a problem hiding this comment.
How can the policy version be evaluated?
There was a problem hiding this comment.
@ctron, there seems to be no version field in a given Policy. Because Policy are git based the policy version is likely managed by using git branches or tags.
There was a problem hiding this comment.
I think we should come up wit a concrete plan here.
There was a problem hiding this comment.
@ctron, I don't understand your question as we evaluate a given policy which is identified from it's version, please clarify.
There was a problem hiding this comment.
policy_version(VARCHAR) - Policy commit hash or tag resolved at validation time
there seems to be no version field in a given Policy. Because Policy are git based the policy version is likely managed by using git branches or tags.
My question is: how do we know which version was used? How to find out the value to put in the field policy_version?
|
|
||
| #### Policy Management | ||
|
|
||
| ec_policies stores external references only. Conforma fetches the actual policy at validation time, which means Trustify does not cache policy content by default. The trade-off: validation always uses the latest policy version, but network failures or policy repo outages will cause execution errors. For private policy repositories, authentication credentials are stored in the configuration JSONB column and must be encrypted at rest; they are never logged. |
There was a problem hiding this comment.
[…] and must be encrypted at rest
That should be documented as well.
There was a problem hiding this comment.
@ctron, right, replaced with using AES crate.
|
|
||
| #### Multi-tenancy | ||
|
|
||
| Policy references are global (shared across all users) in this initial implementation. Per-organization policy namespacing is out of scope here and should be addressed in a dedicated multi-tenancy ADR when Trustify adds org-level isolation more broadly. |
There was a problem hiding this comment.
Maybe collect all of this in a "future work" section.
There was a problem hiding this comment.
@ctron, I'm waiting for confirmation we can start assuming a default policy is defined across the board. As for future evolution, I'll leave it to the PM.
There was a problem hiding this comment.
@ctron, this has been confirmed by PM. We will rely upon a default "Global" Policy. I've updated the Decision section accordingly.
There was a problem hiding this comment.
If this is not relevant for this ADR, can we move into a section "future work"?
|
|
||
| ### Structure of JSON returned from Conforma CLI validation request (from an example) | ||
|
|
||
| ```json |
There was a problem hiding this comment.
I think without any explanation on how this will be used, this doesn't help much.
There was a problem hiding this comment.
@ctron, right, we're now digging at that level of details.
5c04bbe to
2424c62
Compare
ctron
left a comment
There was a problem hiding this comment.
Not sure what the state of the ADR is. Added a few comments, I might have looked too early. Maybe it makes sense putting it back in draft, and then remove the draft when all items are addressed?
|
|
||
| Each SBOM + policy pair has a validation state that follows this lifecycle: | ||
|
|
||
| - **Pending** — initial state, set when an SBOM is associated with a policy (e.g., a default policy assigned at SBOM upload time; upload itself is outside the scope of this ADR). Indicates no validation has been triggered yet for this SBOM against this policy. |
There was a problem hiding this comment.
I'm not aware of any default policy. Does this ADR describe something like this?
If so, then maybe I would again suggest do have those ideas before the "decision" section. Maybe it's just an ordering issue.
| - **Fail** — Conforma validation found policy violations; violation details are linked. | ||
| - **Error** — an execution error occurred (CLI crash, policy fetch failure, timeout). The error is surfaced separately, and the validation can be re-triggered. | ||
|
|
||
| The "In Progress" state serves as a concurrency guard: if a validation is already running for a given SBOM + policy pair, subsequent requests are rejected (409 Conflict), preventing duplicate work. |
There was a problem hiding this comment.
If the validation fails, then the validation need to be reset to "Pending".
Who is in charge of this? What happens when the validation pod just crashes (or gets OOM killed)?
| What is stored where | ||
|
|
||
| - PostgreSQL: validation status, structured violations (JSONB), summary statistics, foreign keys to SBOM and policy. Indexed on sbom_id, status, executed_at. | ||
| - S3/Minio: full raw Conforma JSON report, linked from the DB row via report_url. Keeps DB rows small while preserving audit completeness. |
There was a problem hiding this comment.
S3/Minio
The storage system uses S3 (compatible) stores, or file system. Having "S3/Minio" here, seems to indicate to me that the responsiblity is with S3. Not with the storage system. Also, I didn't see any relationships to the source_document table before.
linked from the DB row via report_url
Not sure how that works with the storage? What does the URL refer to? Maybe an example helps.
| - `report_url` (VARCHAR) - S3 URL to detailed report | ||
| - `executed_at` (TIMESTAMP) | ||
| - `execution_duration_ms` (INTEGER) | ||
| - `conforma_version` (VARCHAR) - Conforma CLI version used (e.g., `v0.8.83`), for reproducibility |
There was a problem hiding this comment.
Please see above about the storage service. I don't think this aligns well with what we have right now.
If we are trying to abstract a bit from conforma, towards some more generic "validation" integration. How could be rename this then?
| GET /api/v2/ec/policies # List policy references | ||
| GET /api/v2/ec/policies/{id} # Get policy reference | ||
| PUT /api/v2/ec/policies/{id} # Update policy reference (admin) | ||
| DELETE /api/v2/ec/policies/{id} # Delete policy reference (admin) |
There was a problem hiding this comment.
I am ok with either way. I guess it's up to someone else to decide if keeping those results is important or not.
In the case it is, then we would have a dangling reference to an entry that no longer exists. We should specify this, as this might create issues when showing information later on. Like showing a name (vs ID) for a result.
|
|
||
| #### Conforma CLI Execution (EC Wrapper) | ||
|
|
||
| The EC Wrapper invokes Conforma via process spawning (e.g., `tokio::process::Command`). All arguments are passed as an array — never as a shell string — to prevent CLI injection. Execution has a configurable timeout (default 5 minutes); large SBOMs are written to a temp file and passed by path rather than piped via stdin, which avoids OOM issues. |
28b1ce2 to
237769b
Compare
5d28223 to
8ac603c
Compare


Summary by Sourcery
Documentation:
Preview: https://github.com/gildub/trustify/blob/adr-ec-integration/docs/adrs/00014-enterprise-contract-integration.md