Skip to content

[ADR] Policy management#2377

Open
gildub wants to merge 20 commits into
guacsec:mainfrom
gildub:policy-management
Open

[ADR] Policy management#2377
gildub wants to merge 20 commits into
guacsec:mainfrom
gildub:policy-management

Conversation

@gildub

@gildub gildub commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

This ADR provides the description of the policy management.

The policies are defined outside of Trustify, initially in Git repositories (Github, Gitlab, etc) meanwhile we need to store some "meta-data" about a given policy, such as the link to the repo, what type of policy is used for (Conforma to start with), and some extra configuration when needed such as authentication details when relevant.

The policy management is the initial building block on the road towards SBOMs validation which will come when the first policy validation solution integration (Conforma API) with Trustify will be available which will permit to validate a SBOM against a specific policy and keep track of such result.

Summary by Sourcery

Documentation:

  • Add ADR describing the policy management data model, API endpoints, permissions, and file structure for integrating external policy references (e.g., Conforma-backed policies) into Trustify.

@sourcery-ai

sourcery-ai Bot commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Reviewer's Guide

Adds a new Architecture Decision Record (ADR 00018) specifying the initial design for policy management in Trustify, including the data model, API surface, permissions, and file/module layout for a new policy module that stores external policy references for later SBOM validation (initially via Conforma).

File-Level Changes

Change Details Files
Define the policy management conceptual and data model, including configuration schema for external policy references and Conforma integration assumptions.
  • Introduce a policy entity that stores only metadata and location of policies (not their content), with fields for id, name, description, type, JSONB configuration, and an optimistic-concurrency revision UUID.
  • Specify the JSON configuration schema (policy_ref, auth, policy_paths, include/exclude, timeout_seconds) for pointing at git-hosted policies and handling encrypted auth credentials.
  • Describe how Conforma-like validation engines will fetch and use external policies at validation time without Trustify caching policy content.
docs/adrs/00018-policy-management.md
Describe Rust-level models and enums that will back the policy API and storage.
  • Define a ValidatorKind enum with variants Null and Conforma to distinguish validation backends.
  • Specify Policy, PolicyRequest, PolicyAuth, and PolicyConfiguration structs with serde attributes for API I/O and JSONB storage.
  • Document that revision (UUID) is surfaced as an ETag for conditional updates and deletes.
docs/adrs/00018-policy-management.md
Specify REST API endpoints, permissions, and error semantics for CRUD policy management.
  • Introduce /api/v2/policy CRUD endpoints with detailed request/response contracts, pagination, filtering by name, and ETag-based optimistic concurrency via IfMatch.
  • Define new fine-grained permissions (create/read/update/delete.policy) and their mapping to existing OIDC scope groups (create/read/update/delete:document).
  • Clarify HTTP status codes for common error conditions (authz failures, name conflicts, precondition failures, references from validation results).
docs/adrs/00018-policy-management.md
Outline security, operational trade-offs, and module/file layout for the new policy component.
  • Document that authentication data for private policy repos is stored encrypted at rest using ring::aead AES-256-GCM and is never logged.
  • Discuss trade-offs of not caching policy content (always latest vs susceptibility to repo/network outages).
  • Propose a new modules/policy crate structure with separate endpoints, model, and service layers including policy_manager for policy configuration management.
docs/adrs/00018-policy-management.md

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot 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.

Hey - I've found 2 issues, and left some high level feedback:

  • Consider using typed enums for ValidatorKind and PolicyAuth.auth_type (instead of generic Null or String) to make invalid policy types/auth modes unrepresentable and reduce runtime validation complexity.
  • The Policy.configuration field is defined as serde_json::Value while a strongly typed PolicyConfiguration struct is specified; it would be clearer and safer to store/return the typed struct directly and only fall back to raw JSON if you explicitly plan for backend-specific extensions.
  • The DELETE semantics specify 204 even when the policy is already deleted; if you want optimistic concurrency to matter here, you may want to clarify whether a missing resource with a matching IfMatch should still return 204 or a 404 to avoid surprising clients.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Consider using typed enums for `ValidatorKind` and `PolicyAuth.auth_type` (instead of generic `Null` or `String`) to make invalid policy types/auth modes unrepresentable and reduce runtime validation complexity.
- The `Policy.configuration` field is defined as `serde_json::Value` while a strongly typed `PolicyConfiguration` struct is specified; it would be clearer and safer to store/return the typed struct directly and only fall back to raw JSON if you explicitly plan for backend-specific extensions.
- The DELETE semantics specify `204` even when the policy is already deleted; if you want optimistic concurrency to matter here, you may want to clarify whether a missing resource with a matching `IfMatch` should still return `204` or a `404` to avoid surprising clients.

## Individual Comments

### Comment 1
<location path="docs/adrs/00018-policy-management.md" line_range="145" />
<code_context>
+The trade-off:
+
+- Validation always uses the latest policy content from the referenced branch or tag, 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 encrypted at rest using `ring::aead` (AES-256-GCM authenticated encryption); they are never logged The `ring` crate is already a direct dependency of the project (used for digest hashing), so no new dependency is required.
+
+## Trustify API Endpoints
</code_context>
<issue_to_address>
**issue (typo):** Add missing punctuation between "logged" and "The` ring crate" to fix the run-on sentence.

The sentence should read "...they are never logged. The `ring` crate is already a direct dependency..." to avoid the run-on.

```suggestion
- For private policy repositories, authentication credentials are stored in the `configuration` JSONB column and encrypted at rest using `ring::aead` (AES-256-GCM authenticated encryption); they are never logged. The `ring` crate is already a direct dependency of the project (used for digest hashing), so no new dependency is required.
```
</issue_to_address>

### Comment 2
<location path="docs/adrs/00018-policy-management.md" line_range="280-289" />
<code_context>
+| header | `IfMatch` | `Option<String>` | ETag value, revision to update |
</code_context>
<issue_to_address>
**issue (typo):** Use the standard HTTP header spelling `If-Match` instead of `IfMatch` in the documentation tables.

In the PUT and DELETE request tables, the header is listed as `IfMatch`; please update it to `If-Match` to match the actual HTTP header name and keep the docs accurate.

Suggested implementation:

```
| header | `If-Match` | `Option<String>` | ETag value, revision to update |

```

There is also a DELETE request table mentioned in your review comment where the header is listed as `IfMatch`. Apply the same textual change in that table: replace the header name `IfMatch` with `If-Match` so both PUT and DELETE documentation consistently use the correct HTTP header spelling.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread docs/adrs/00018-policy-management.md Outdated
Comment thread docs/adrs/00018-policy-management.md Outdated
@gildub gildub requested a review from ctron June 2, 2026 08:32
@gildub

gildub commented Jun 2, 2026

Copy link
Copy Markdown
Contributor Author

@sourcery-ai resolve

@gildub

gildub commented Jun 2, 2026

Copy link
Copy Markdown
Contributor Author

@sourcery-ai dismiss

@gildub gildub force-pushed the policy-management branch from 1d2954e to 40cc1d7 Compare June 2, 2026 12:22

@ctron ctron 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.

Looks good. Some changes and clarifications needed.

Comment thread docs/adrs/00018-policy-management.md Outdated
Comment thread docs/adrs/00018-policy-management.md Outdated
Comment thread docs/adrs/00020-policy-management.md
Comment thread docs/adrs/00018-policy-management.md Outdated
Comment thread docs/adrs/00018-policy-management.md Outdated
Comment thread docs/adrs/00018-policy-management.md Outdated
Comment thread docs/adrs/00018-policy-management.md Outdated
Comment thread docs/adrs/00018-policy-management.md Outdated
Comment thread docs/adrs/00018-policy-management.md Outdated
Comment thread docs/adrs/00018-policy-management.md Outdated
@gildub gildub force-pushed the policy-management branch from 40cc1d7 to 90d6432 Compare June 2, 2026 15:13
@gildub gildub requested a review from ctron June 3, 2026 07:58
@gildub gildub changed the title Initial ADR for policy management [ADR] Policy management Jun 3, 2026
@gildub gildub added the ADR label Jun 3, 2026
@gildub gildub force-pushed the policy-management branch from cdeeb10 to 062e045 Compare June 3, 2026 13:43
@gildub gildub added the enhancement New feature or request label Jun 3, 2026
@gildub gildub force-pushed the policy-management branch 3 times, most recently from bab44fe to 4b88e77 Compare June 8, 2026 12:24

```rust
/// extending modules/importer/src/model/mod.rs
pub enum ImporterConfiguration {

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.

Looks like a copy and paste error

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@ctron, it isn't, don't we need this in order to wrap the PolicyConfiguration under the patter of ImporterConfiguration, or may we don't need to show that part ?

Comment thread docs/adrs/00018-policy-management.md Outdated
schemars::JsonSchema,
)]
#[serde(rename_all = "camelCase")]
pub struct PolicyImporter {

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.

Why is this called "Importer"?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Right, I suppose it's because it's wrapped under the ImporterConfiguration but it makes more sense to dub it PolicyConfiguration

#[serde(rename_all = "camelCase")]
pub struct PolicyImporter {
#[serde(flatten)]
pub common: CommonImporter,

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.

Looks like a copy and paste error.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@ctron, isn't that needed to wrap the PolicyConfiguration with the ImporterConfiguration ?

Comment thread docs/adrs/00018-policy-management.md Outdated
name: String,
description: String,
policy_type: PolicyType,
configuration: PolicyImporter,

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.

Looks like a copy and paste error

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

PolicyRequest is just the API input shape, not the stored entity.

Comment thread docs/adrs/00018-policy-management.md Outdated
struct PolicyRequest {
name: String,
description: String,
policy_type: PolicyType,

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.

This is splitting now the discriminator and the data into two fields. It looks like with no validation between them. Why not fully adopt the existing pattern:

pub enum ImporterConfiguration {
Sbom(SbomImporter),
Csaf(CsafImporter),
Osv(OsvImporter),
Cve(CveImporter),
ClearlyDefined(ClearlyDefinedImporter),
ClearlyDefinedCuration(ClearlyDefinedCurationImporter),
Cwe(CweImporter),
Quay(QuayImporter),
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Right, I removed the PolicyRequest

Comment thread docs/adrs/00018-policy-management.md Outdated
#[derive(Serialize, Deserialize)]
struct PolicyAuth {
#[serde(rename = "type")]
auth_type: AuthType,

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.

We could just name it type (or r#type).

@gildub gildub force-pushed the policy-management branch from 4b88e77 to 94a9feb Compare June 9, 2026 14:05
Comment thread docs/adrs/00018-policy-management.md Outdated
/// The policy reference information
#[derive(Serialize, Deserialize)]
struct Policy {
id: Uuid,

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.

This must be String.

@gildub gildub requested a review from ctron June 11, 2026 10:49
@gildub gildub force-pushed the policy-management branch 2 times, most recently from 88fac5c to ecbdb9a Compare June 16, 2026 10:44
@gildub gildub force-pushed the policy-management branch from ecbdb9a to 571bc74 Compare June 24, 2026 08:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ADR enhancement New feature or request

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

2 participants