Develocity Provenance Governor
Develocity Provenance Governor is an enterprise solution designed to help automate governance, compliance, and risk for the software supply chain. It enables organizations to define, manage, and enforce provenance and attestation policies for software packages, ensuring that only trusted and compliant artifacts are promoted and consumed across environments.
1. How it works
Leveraging the build data in Develocity, Develocity Provenance Governor collects, verifies, and evaluates provenance data and attestations. The product offers detailed provenance attestations, declarative domain-aware policies, and automated evaluation, empowering teams to:
-
Enforce organizational and regulatory requirements for software provenance
-
Prevent the use of untrusted or non-compliant artifacts
-
Gain visibility into the origin and integrity of software components
-
Streamline compliance reporting and incident response
1.1. Key Concepts
Below are the terms and concepts you need to understand to use Develocity Provenance Governor:
-
Attestations are signed statements about the origin (or provenance) of a software package, including details about its build process, dependencies, and other metadata. Attestations can be used to verify the integrity and authenticity of software packages.
-
Policies define rules and conditions that software packages must adhere to. You can use policies to prevent non-compliant or untrusted packages from being released, deployed, or used.
-
Policy scans evaluate packages against defined policies and report on the package’s level of compliance.
1.2. Components
1.3. Flow
Below is a typical flow for using Develocity Provenance Governor in a software supply chain:
-
A build runs on a Continuous Integration (CI) system and:
-
Produces a software package (for example, a JAR file).
-
Publishes a Build Scan to Develocity (Build Scans capture detailed information about the build process).
-
Uploads the software package to a package repository (for example, JFrog Artifactory).
-
Calls Develocity Provenance Governor to generate and publish attestations for the software package.
-
-
Develocity Provenance Governor generates attestations based on Build Scan data from Develocity that was collected while building the software package.
-
After an attestation is generated, Develocity Provenance Governor signs the attestation using a private key.
-
The signed attestation is published to an attestation store. Develocity Provenance Governor supports publishing attestations to JFrog Artifactory.
-
-
A later CI or Continuous Deployment (CD) job calls Develocity Provenance Governor to perform a policy scan on the software package.
-
Develocity Provenance Governor performs a policy scan to evaluate policies against the software package to determine if it is compliant with organization rules and requirements. Develocity Provenance Governor uses the previously published attestations to evaluate policies.
-
The result of the policy scan is returned to the calling job.
-
Based on the results of the policy scan, the job can decide to proceed or fail.
-
|
Once published, attestations generated by Develocity Provenance Governor can also be used with JFrog Evidence features and functionality. |
2. Getting set up
Develocity Provenance Governor is delivered as a containerized application designed for Kubernetes deployment. While the application is cloud-native by design, proper setup requires careful configuration of prerequisites, credentials, and policies.
2.1. Prerequisites
Before deploying Develocity Provenance Governor, ensure you have the following prerequisites. These are organized in a logical order that matches the typical installation workflow: infrastructure setup, external integrations, and security configuration.
|
Recommended Setup Order: Infrastructure (set up first):
External Integrations (configure before deployment):
Security (prepare before first use):
Planning:
|
2.1.1. Develocity License
Develocity Provenance Governor uses your existing Develocity license - no separate license is required. Any valid Develocity license works; no special entitlements are needed. If you are already a Develocity customer, you can use your existing license. If you do not have a Develocity license, contact Gradle’s sales team and mention that you need access for "Develocity Provenance Governor".
2.1.2. Kubernetes Cluster
Develocity Provenance Governor is designed to run in a Kubernetes environment. You will need to install it into a Kubernetes cluster. The Kubernetes cluster must have an Ingress Controller.
|
Develocity Provenance Governor can be deployed in environments other than Kubernetes. If you need to run Develocity Provenance Governor outside of Kubernetes please open a support ticket and describe your deployment requirements. |
2.1.3. Cluster Resources
Plan for these resource requirements: By default, the combined Kubernetes resource requests are 2 CPUs and 1 GiB memory per replica. These values are configurable via Kubernetes Deployment values, but lower values may impact performance.
2.1.4. JFrog Artifactory with Evidence Management
|
Artifactory Enterprise+ license (version 7.104.2 or later) is required. The Evidence Management feature is mandatory for Develocity Provenance Governor operation. Without Artifactory configured with this feature, Develocity Provenance Governor cannot store or retrieve attestations. |
Develocity Provenance Governor requires Artifactory as the attestation store. All attestations are stored in and retrieved from Artifactory, making it a critical component of your deployment.
Requirements:
-
Artifactory version 7.104.2 or later
-
Enterprise+ license
-
Evidence Management feature enabled with support for external evidence
-
Network access from the Develocity Provenance Governor deployment to the Artifactory instance
-
Artifactory Access Token or Identity Token with the following permissions:
-
Read - to retrieve attestations
-
Annotate - to attach evidence metadata to artifacts
-
2.1.5. Develocity Instance
Develocity Provenance Governor uses Develocity Build Scan data to generate attestations. It requires network access to a Develocity instance.
Develocity Provenance Governor requires a valid Develocity access key for a user with the “Access build data via the API” permission. If the Develocity instance is using Project-level Access Control, Develocity Provenance Governor will only be able to publish attestations for Build Scan data in projects that the user has access to.
The minimum version of Develocity that Develocity Provenance Governor supports is 2023.3. Develocity Provenance Governor supports publishing attestations from Build Scan data from the following build tools:
-
Gradle, with Develocity plugin version 1.16 or later.
-
JVM attestations for Gradle toolchains are only supported for plugin 3.11 or later.
-
-
Maven, with Develocity extension version 1.4 or later.
We recommend using the latest available version of Develocity and its build tool integrations for the best experience.
2.1.6. Signing Key Pair
Develocity Provenance Governor cryptographically signs all attestations to ensure authenticity and prevent tampering. You need to generate a signing key pair before deployment. The private key remains with Develocity Provenance Governor and is used to sign attestations. The public key must be registered in your Artifactory instance to allow verification of signed attestations.
Supported Key Types:
We support Ed25519, RSA, and Elliptic Curve keys. Ed25519 is recommended because it provides strong security (equivalent to 128-bit security) with significantly smaller keys and faster operations than RSA or ECDSA.
Generating a Key Pair:
Develocity Provenance Governor needs to be configured with a signing key pair in PEM format. You can generate an Ed25519 key pair using OpenSSL:
openssl genpkey -algorithm Ed25519 -out ./key-pair.private-pem
openssl pkey -in ./key-pair.private-pem -pubout -out ./key-pair.public-pem
|
Keep the private key secure. You’ll configure it as a Kubernetes secret during deployment. The public key will be registered in Artifactory to verify attestation signatures. |
2.1.7. Hostname
Develocity Provenance Governor needs a hostname. It will be used in its Ingress. Ensure that the hostname’s DNS is configured to work with the Kubernetes cluster’s Ingress Controller.
2.1.8. TLS Certificate
You’ll need a TLS (Transport Layer Security) certificate for your hostname to enable SSL (Secure Sockets Layer). While SSL/TLS is technically optional, it is strongly recommended for production environments.
Options include:
-
Using an existing organizational certificate
-
Generating one with cert-manager and Let’s Encrypt (see deployment section for details)
-
Using a self-signed certificate for testing (not recommended for production)
2.2. Deployment
Develocity Provenance Governor is provided as a container image that runs on a Kubernetes cluster (recommended) or a local Docker/Kubernetes environment. Make sure you have the prerequisites detailed in Prerequisites before proceeding.
2.2.1. Audience
This guide is written for a Platform / Infrastructure Engineer. It assumes:
-
Basic familiarity with Kubernetes (namespaces, secrets, configmaps, deployments, ingress)
-
Ability to obtain a Develocity license file (
develocity.license) -
(Optional) Ability to obtain access tokens/keys for Develocity and Artifactory instances
-
Access to a DNS domain (optional, for public HTTPS ingress)
2.2.2. Quick Start
Want to get started quickly with a local k3d cluster and basic HTTP ingress?
See the Quick Start Guide for condensed setup instructions.
The quick start will guide you through:
-
Creating a local k3d cluster
-
Deploying Develocity Provenance Governor with basic HTTP ingress
-
Verifying the deployment
After completing the quick start, return to the sections below to configure additional features like authentication, integrations, and policies.
2.2.3. Deployment Flow Overview
The recommended order is:
-
Choose / create a Kubernetes cluster (local k3d or existing)
-
Create namespace + required secrets (registry + license)
-
Configure Ingress (HTTP, then HTTPS + cert-manager) - Optional
-
Deploy the core workload (ServiceAccount, Services, Deployment, NetworkPolicy)
-
Create placeholder Secrets/ConfigMaps for dynamic configuration (
secrets,properties,policies) -
Add integrations (Develocity instances, Artifactory instances)
-
Enable authentication (Basic and/or OIDC)
-
Define policies (AccessControl manifests)
-
Roll out config changes as needed
Estimated setup time:
-
Local k3d (Quick Start): 15-30 minutes
-
Production setup with all integrations: 2-4 hours (depending on external service coordination and certificate setup)
2.2.4. Select Kubernetes Distribution
Before proceeding ensure access to a Kubernetes cluster has been provided, otherwise a local k3d cluster is also supported.
k3d
brew install k3d
k3d cluster create --port "80:80@loadbalancer"
2.2.5. Prepare the Kubernetes Namespace and Required Secrets
You must create a Kubernetes namespace and the secrets needed for the application to start.
Create Kubernetes Namespace
kubectl create namespace develocity-provenance-governor
Docker Registry Secret (Required)
Authenticate to registry.gradle.com to pull the product image.
kubectl create secret docker-registry registry-secret \
--namespace develocity-provenance-governor \
--docker-server=https://registry.gradle.com \
--docker-username=user \
--docker-password=$(cat ./develocity.license)
2.2.6. Ingress (Optional)
No default ingress is provided. Choose what aligns with organizational standards. Below examples cover:
-
Local development (nip.io hostname)
-
HTTPS with cert-manager & Let’s Encrypt
kubectl --namespace develocity-provenance-governor apply -f - <<EOF
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: api.127.0.0.1.nip.io
spec:
rules:
- host: api.127.0.0.1.nip.io
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api-http
port:
number: 80
EOF
kubectl get ingress api.127.0.0.1.nip.io --namespace develocity-provenance-governor
NAME CLASS HOSTS ADDRESS PORTS AGE
http traefik api.127.0.0.1.nip.io 172.18.0.3 80 15s
curl api.127.0.0.1.nip.io -i
HTTP/1.1 401 Unauthorized
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Length: 0
Expires: 0
Pragma: no-cache
Referrer-Policy: no-referrer
Www-Authenticate: Basic realm="Realm"
...
Ingress with cert-manager
Alternative, ingress manifest using cert-manager, nginx, and signed certificate from Let’s Encrypt.
The ingress resource, can be used to expose the api service outside the cluster.
Modify the provided manifest to reflect the domain that you control paying close attention to tls[0].hosts[0] and rules[0].host.
kubectl --namespace develocity-provenance-governor apply -f - <<EOF
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: https
spec:
tls:
- hosts:
- provenance-governor.example.com
secretName: https-api-tls
rules:
- host: provenance-governor.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api-http
port:
number: 80
EOF
At this point, the ingress controller might use a self-signed certificate provided as a default.
kubectl get ingress https --namespace develocity-provenance-governor
NAME CLASS HOSTS ADDRESS PORTS AGE
https traefik provenance-governor.example.com xxx.xxx.xx.x 80, 443 15s
If not already deployed, install cert-manager
kubectl --namespace develocity-provenance-governor create --edit -f - <<EOF
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: lets-encrypt
spec:
acme:
# The ACME server URL
server: https://acme-v02.api.letsencrypt.org/directory
# Email address used for ACME registration
email: user@example.com
# Name of a secret used to store the ACME account private key
privateKeySecretRef:
name: lets-encrypt
# Enable the HTTP-01 challenge provider
solvers:
- http01:
ingress:
ingressClassName: nginx
EOF
| This will create a certificate issuer using the Production Instance of Let’s Encrypt. Edit accordingly based on desired certificate issuer implementation. If using Let’s Encrypt, ensure the ingress is publicly accessible and can handle a http01 challenge provider request to complete certificate issuance. Also, be sure to update the email address. |
kubectl describe issuer lets-encrypt \
--namespace develocity-provenance-governor
Detailed issuer information should be returned along with Status.Status: True and Status.Type: Ready.
Edit the https ingress resource to use the lets-encrypt issuer instead of the self signed certificate issuer.
kubectl edit ingress https \
--namespace develocity-provenance-governor
cert-manager.io/issuer: lets-encrypt to annotations:metadata:
annotations:
cert-manager.io/issuer: lets-encrypt
$ kubectl get certificate \
--namespace develocity-provenance-governor
NAME READY SECRET AGE
https-api-tls True https-api-tls 2m31s
$ curl https://provenance-governor.example.com -i HTTP/2 401 …
In this example, the request to https://provenance-governor.example.com returns a 401 Unauthorized status code because no credentials were provided.
This confirms that the Ingress is correctly routing traffic to the service and that the service is up and running.
To verify the service health:
curl https://provenance-governor.example.com/readyz -i
No SSL negotiation exceptions should be thrown and a 401 should be returned.
2.2.7. Deploy Core Components
Apply the workload manifests. (See Quick Start)
Download the manifest.yaml file.
kubectl --namespace develocity-provenance-governor apply -f manifest.yaml
kubectl rollout status deployment/api \
--timeout=90s \
--namespace develocity-provenance-governor
Expected output: deployment "api" successfully rolled out.
If rollout fails:
-
Verify
registry-secretcredentials and image digest/tag -
Verify
licensesecret presence and correct file content
kubectl logs deployment/api \
--namespace develocity-provenance-governor | grep -i license
Develocity license enabled, with license [...]
Started ProvenanceGovernor in ...
2.2.8. Create Placeholders for Dynamic Configuration (Optional but Recommended)
The Deployment mounts (optionally) these resources:
Resource |
Kind |
Purpose |
Required |
Mounted Path |
license |
Secret |
Develocity product license |
Yes |
/workspace/config/license |
secrets |
Secret |
Sensitive values (access tokens, private keys) |
No |
/workspace/config/secrets |
properties |
ConfigMap |
Non-sensitive configuration (URIs, public keys) |
No |
/workspace/config/properties |
policies |
ConfigMap |
Policy manifests |
No |
/workspace/config/policies |
Create empty resources to prepare for configuration:
kubectl create secret generic secrets --namespace develocity-provenance-governor || true
kubectl create configmap properties --namespace develocity-provenance-governor || true
kubectl create configmap policies --namespace develocity-provenance-governor || true
2.2.9. Configure Develocity Instances (Optional)
Use one or more Develocity instances as attestation data sources.
Key patterns:
-
Secret:
develocity.instances.<NAME>.access-key -
ConfigMap:
develocity.instances.<NAME>.uri
<NAME> must be alphanumeric plus dashes or underscores.
kubectl edit secret secrets --namespace develocity-provenance-governor
Add access key (use stringData: when adding new values):
stringData:
develocity.instances.MY_INSTANCE.access-key: my-access-key-for-develocity
kubectl edit configmap properties --namespace develocity-provenance-governor
Add URI:
data:
develocity.instances.MY_INSTANCE.uri: https://develocity.example.com
Rollout & Verify:
kubectl rollout restart deployment/api --namespace develocity-provenance-governor
kubectl rollout status deployment/api --namespace develocity-provenance-governor --timeout=90s
kubectl logs deployment/api --namespace develocity-provenance-governor | grep -i "Develocity support enabled"
Expected log snippet:
Develocity support enabled, for instance [MY_INSTANCE:https://develocity.example.com]
Troubleshooting: Repeated Retrying [n/10] request … indicates connectivity or credential issues.
2.2.10. Configure Artifactory Instances (Optional)
Used to publish attestation data.
Key patterns:
-
Secret:
artifactory.instances.<NAME>.access-token(token preferred over legacy key) -
ConfigMap:
artifactory.instances.<NAME>.uri
kubectl edit secret secrets --namespace develocity-provenance-governor
Add token:
stringData:
artifactory.instances.MY_ARTIFACTORY.access-token: my-access-token-for-artifactory
kubectl edit configmap properties --namespace develocity-provenance-governor
Add URI:
data:
artifactory.instances.MY_ARTIFACTORY.uri: https://artifactory.example.com
Rollout & Verify:
kubectl rollout restart deployment/api --namespace develocity-provenance-governor
kubectl rollout status deployment/api --namespace develocity-provenance-governor --timeout=90s
kubectl logs deployment/api --namespace develocity-provenance-governor | grep -i "Artifactory support enabled"
Expected log snippet:
Artifactory support enabled, for instance [MY_ARTIFACTORY:https://artifactory.example.com]
2.2.11. Configure Signing Keys (Optional but Recommended for Attestations)
Attestations are wrapped in a Dead Simple Signing Envelope (DSSE) signed by a key pair.
Required key property patterns:
-
Secret (private key, base64 PEM):
signing.key.<FRIENDLY_KEY_NAME>.private-pem -
ConfigMap (public key PEM block):
signing.key.<FRIENDLY_KEY_NAME>.public-pem
Choose a naming convention like <ORG_OR_PRODUCT>_YYYY-MM-DD for rotation clarity.
Create Ed25519 Key Pair
Recommended (128-bit security, small key sizes/signatures).
openssl genpkey \
-algorithm Ed25519 \
-out private-key.pem
openssl pkey \
-in private-key.pem \
-pubout \
-out public-key.pem
kubectl edit secret secrets \
--namespace develocity-provenance-governor
Base64 and add private key (Secret):
base64 -i private-key.pem | pbcopy
kubectl edit secret secrets --namespace develocity-provenance-governor
Paste under data: (Kubernetes will not modify pasted base64):
data:
signing.key.FRIENDLY_KEY_NAME.private-pem: <PASTE_BASE64_PRIVATE_KEY>
cat public-key.pem | sed 's/^/ /' | pbcopy
kubectl edit configmap properties --namespace develocity-provenance-governor
Paste under data::
data:
signing.key.FRIENDLY_KEY_NAME.public-pem: |
# PASTE THE PUBLIC KEY BLOCK HERE FROM CLIPBOARD
-----BEGIN PUBLIC KEY-----
...
-----END PUBLIC KEY-----
Rollout & Verify:
kubectl rollout restart deployment/api --namespace develocity-provenance-governor
kubectl logs deployment/api --namespace develocity-provenance-governor | grep -i "Signature support enabled"
Expected log:
Signature support enabled, for key pair [name:FRIENDLY_KEY_NAME:keyid:XXXXXX:signing-algorithm:ed25519]
Key ID is a 6-character abbreviation of the SHA-256 digest of the public key.
Other Supported Algorithms
Elliptic Curve (ECDSA) and RSA are also supported. Substitute commands below; follow the same secret/configmap procedure.
2.2.12. Authentication (Optional)
Supported schemes:
Enable Basic Authentication
Add identities under:
-
Secret key pattern:
basic.identities.<NAME>
<NAME> is a human-friendly identifier.
No default credentials exist.
kubectl edit secret secrets --namespace develocity-provenance-governor
stringData:
basic.identities.some-user: "{noop}some-pass"
Recommendation: Replace {noop} with {bcrypt} and supply a bcrypt-hashed password.
kubectl rollout restart deployment/api \
--namespace develocity-provenance-governor
kubectl logs deployment/api \
--namespace develocity-provenance-governor |
grep -i "Basic Identity support"
Basic Identity support enabled, for identity [some-user]
2.2.13. Policies (Optional)
Policies are YAML documents stored inside the policies ConfigMap.
Each key corresponds to a file-style name ending with .yaml.
Access Control Policies
Define who can do what on which resources.
identityMatchingStrategy supported:
-
withBasicIdentity– must match a key underbasic.identities.<NAME>insecrets -
withOidc– relies on issuer discovery; ensure network accessibility
canPerform supported actions:
* publish-attestations - publish DSSE-wrapped attestations to an Attestation Store (e.g., Artifactory)
* publish-policy-scans - publish policy scan results to an Attestation Store
withResources supported patterns:
-
pkg:pkg-type/pkg-namespace/pkg-name@pkg-vesion- specific Package URL pattern to match or use wildcards:-
pkg:maven/*- all Maven packages -
pkg:oci/*- all OCI packages (container images) -
pkg:maven/org.example/@- all Maven packages inorg.examplenamespace and any version -
pkg:maven/org.example/my-app@1.0.0- specific Maven package -
pkg:oci/image-name@v1*- specific OCI image with wildcard version
-
-
*:REPLACE_WITH_DV_INSTANCE_NAME/*- allow to read build scans from the Develocity Instance to source data for attestations. -
*:REPLACE_WITH_ARTIFACTORY_INSTANCE_NAME/*- allow to publish attestations to the Artifactory Instance. Replace*with the repository name in artifactory to restrict access further. -
*:*/*- allows authenticated identity access to all resources (not recommended for production use)
Basic Identity Policy Example
kubectl edit configmap policies --namespace develocity-provenance-governor
data:
basic-identity-some-user-full-access.yaml: |
apiVersion: policy.gradle.com/v1
kind: AccessControl
metadata:
name: basic-identity-some-user-full-access
spec:
identityMatchingStrategy:
withBasicIdentity:
- withName: "some-user"
canPerform:
- publish-attestations
- publish-policy-scans
withResources:
- "*:*/*"
OIDC Policy Example (GitHub Actions)
kubectl edit configmap policies --namespace develocity-provenance-governor
data:
oidc-github-action-full-access.yaml: |
apiVersion: policy.gradle.com/v1
kind: AccessControl
metadata:
name: oidc-github-action-full-access
spec:
identityMatchingStrategy:
withOidc:
- fromIssuerUri: https://token.actions.githubusercontent.com
withClaims:
job_workflow_ref: org/automation-repo/.github/workflows/build-image.yml@*
canPerform:
- publish-attestations
- publish-policy-scans
withResources:
- "*:*/*"
Public Key Verification Policy Example
kubectl edit configmap policies --namespace develocity-provenance-governor
data:
public-key-verification-policy.yaml: |
apiVersion: policy.gradle.com/v1
kind: TrustedPublicKeys
metadata:
name: public-keys
spec:
resultsLabels: []
description: Public keys trusted for attestations.
remediation: Update the list of trusted public keys to ensure only verified attestations are accepted.
keys:
DEPLOYMENT_KEY_2025_10_01:
pem: |
-----BEGIN PUBLIC KEY-----
....
-----END PUBLIC KEY-----
Replace DEPLOYMENT_KEY_2025_10_01 and the PEM block with your actual trusted public keys, for example the ones used to sign attestations.
kubectl rollout restart deployment/api \
--namespace develocity-provenance-governor
kubectl rollout status deployment/api \
--namespace develocity-provenance-governor \
--timeout=90s
kubectl logs deployment/api \
--namespace develocity-provenance-governor |
grep -i "Loading Policy Resource from file"
Loading Policy Resource from file [/workspace/config/policies/public-key-verification-policy.yaml]
2.2.14. Troubleshooting Deployment Rollouts
Common rollout hang:
Waiting for deployment "api" rollout to finish: 1 old replicas are pending termination...
error: timed out waiting for the condition
Inspect pods:
kubectl get pods --namespace develocity-provenance-governor
Identify failing pod (e.g., CrashLoopBackOff) and fetch logs:
kubectl logs api-<POD_ID> --namespace develocity-provenance-governor
Example configuration error:
***************************
APPLICATION FAILED TO START
***************************
Failed to bind properties under 'artifactory.instances.INSTANCE_NAME_GOES_HERE' ... Reason: java.lang.IllegalArgumentException: uri must not be null
Remediation:
-
Missing URI – edit
propertiesConfigMap keyartifactory.instances.<NAME>.uri -
Missing token – edit
secretskeyartifactory.instances.<NAME>.access-token
After fixing, restart:
kubectl rollout restart deployment/api --namespace develocity-provenance-governor
kubectl rollout status deployment/api --namespace develocity-provenance-governor --timeout=90s
2.2.15. Verification and Next Steps
After completing the deployment, verify that Develocity Provenance Governor is running correctly:
-
Check Pod Status
kubectl get pods -n develocity-provenance-governorYou should see the
apipod inRunningstate with1/1ready. -
Check Application Logs
kubectl logs deployment/api -n develocity-provenance-governor --tail=50Look for messages indicating: License loaded successfully Integrations enabled (e.g., "Develocity support enabled", "Artifactory support enabled") Policies loaded (if configured) No error messages
-
Test API Accessibility
curl -i http://your-provenance-governor-hostnameYou should receive a
401 Unauthorizedresponse, which confirms the application is running and authentication is required.The actuator endpoints (health, readiness, liveness) are exposed on port 9090 and not accessible through the public ingress. Develocity Provenance Governor also exposes
/livezand/readyzendpoints on the main application port for health checking when Kubernetes probes are enabled. -
Verify Integration Configuration
Check that your configured integrations were loaded:
kubectl logs deployment/api -n develocity-provenance-governor | grep "support enabled"
|
Successfully deployed? If all verification steps passed and you’re ready to start using Develocity Provenance Governor, proceed to Section 3: Using Develocity Provenance Governor to learn how to publish attestations and evaluate policies. |
What to Do Next:
-
Configure Your First Integration - If you haven’t already, set up connections to Develocity and Artifactory. See Application Configuration.
-
Set Up Authentication - Configure access control policies to secure your API. See Access Control.
-
Write Your First Policy - Define policies for your software supply chain governance. See Writing Policies.
-
Publish Test Attestations - Try publishing attestations for a test package. See Using Develocity Provenance Governor.
-
Integrate with CI/CD - Add Develocity Provenance Governor to your build and deployment pipelines. See GitHub Actions or Integration with Other CI/CD Systems.
If you encounter issues, consult the Troubleshooting section.
2.2.16. Summary Cheat Sheet
Integration |
Secret Key Pattern |
ConfigMap Key Pattern |
Mandatory |
Notes |
License |
(file) |
n/a |
Yes |
Provided via |
Registry Auth |
|
n/a |
Yes |
JSON auth file for image pulls |
Develocity Instance |
|
|
No |
Multiple supported |
Artifactory Instance |
|
|
No |
Token preferred |
Signing Key (Private) |
|
n/a |
No |
Base64 PEM |
Signing Key (Public) |
n/a |
|
No |
PEM block |
Basic Identity |
|
n/a |
No |
|
Policies |
n/a |
|
No |
AccessControl docs |
2.3. Application Configuration
Configuration for Develocity Provenance Governor uses Kubernetes-native resources that are mounted into the container at startup:
-
ConfigMap 'properties' - Non-sensitive settings (URIs, public keys)
-
Secret 'secrets' - Sensitive data (access keys, tokens, private keys)
-
ConfigMap 'policies' - YAML policy definitions
Changes to these resources take effect after restarting the deployment.
2.3.1. Configuration Overview
Configure Develocity Provenance Governor in the following order:
| Component | Description | Required |
|---|---|---|
Connect to Develocity instance(s) to retrieve build scan data for attestation generation |
✓ Required |
|
Configure at least one storage backend: Artifactory or S3 |
✓ Required (choose one or both) |
|
Generate and configure signing keys for cryptographically signing attestations |
Recommended |
|
Define who can access which resources via Access Control policies |
✓ Required |
|
Define policy scans and validation rules for evaluating packages |
Optional (required for policy evaluation) |
|
Minimum viable configuration requires:
Recommended configuration also includes:
|
2.3.2. How to Configure Properties
Develocity Provenance Governor reads configuration from two Kubernetes resources:
-
ConfigMap
properties- Non-sensitive configuration (URIs, options, public keys) -
Secret
secrets- Sensitive configuration (access tokens, private signing keys)
There are two ways to structure configuration in these resources:
Option 1: Individual Property Keys (Recommended for few properties)
Each property is a separate key in the ConfigMap or Secret:
apiVersion: v1
kind: ConfigMap
metadata:
name: properties
namespace: develocity-provenance-governor
data:
develocity.instances.prod.uri: "https://develocity.example.com"
s3.instances.prod-bucket.region: "us-east-1"
s3.instances.prod-bucket.bucket-name: "dpg-attestations"
apiVersion: v1
kind: Secret
metadata:
name: secrets
namespace: develocity-provenance-governor
type: Opaque
stringData:
develocity.instances.prod.access-key: "your-access-key-here"
artifactory.instances.main.access-token: "your-token-here"
Option 2: Single application.yml File (Recommended for many properties)
All properties in a single YAML file as one key:
apiVersion: v1
kind: ConfigMap
metadata:
name: properties
namespace: develocity-provenance-governor
data:
application.yml: |
develocity:
instances:
prod:
uri: "https://develocity.example.com"
s3:
instances:
prod-bucket:
region: "us-east-1"
bucket-name: "dpg-attestations"
apiVersion: v1
kind: Secret
metadata:
name: secrets
namespace: develocity-provenance-governor
type: Opaque
stringData:
application.yml: |
develocity:
instances:
prod:
access-key: "your-access-key-here"
artifactory:
instances:
main:
access-token: "your-token-here"
signing:
keys:
- key: |
-----BEGIN PRIVATE KEY-----
MHcCAQEEIL...
-----END PRIVATE KEY-----
|
Choose the approach that works best for your organization:
Both approaches can be mixed - some properties in individual keys, others in application.yml files. |
Each section below details the configuration for these components.
2.3.3. Attestation Storage
Develocity Provenance Governor requires at least one attestation storage backend to publish attestations. You can configure:
-
Amazon S3 - Store attestations in S3 buckets
-
Artifactory - Store attestations using Artifactory’s evidence store
You may configure both storage backends to publish attestations to multiple locations simultaneously.
2.3.4. Develocity
To configure access to a Develocity instance, configure the following application properties:
develocity.instances.<instance-name>.uri=https://develocity.example.com (1)
| 1 | <instance-name> is an identifier you choose (e.g., 'prod-dv' or 'main').
This name is used in access control policies and log messages.
Use alphanumeric characters, dashes, or underscores. |
Provide a Develocity access key in the sensitive application properties:
develocity.instances.<instance-name>.access-key=************ (your access key here)
2.3.5. Artifactory (Optional)
To configure access to an Artifactory instance for attestation storage, configure the following application properties:
artifactory.instances.<instance-name>.uri=https://artifactory.example.com (1)
| 1 | <instance-name> is a name you choose to identify this Artifactory instance. |
|
Artifactory configuration is optional. If you’re using S3 for attestation storage, you don’t need to configure Artifactory unless you want to publish attestations to both storage backends. |
Provide an Artifactory access or ID token in the sensitive application properties (Secret secrets):
artifactory.instances.<instance-name>.access-token=************ (your access token here)
Advanced Artifactory Configuration
The following advanced properties can be configured for each Artifactory instance:
artifactory.instances.<instance-name>.path=/artifactory (1)
artifactory.instances.<instance-name>.graphql-path=/onemodel/api/v1/graphql (2)
artifactory.instances.<instance-name>.evidence-path=/evidence/api/v1/subject (3)
artifactory.instances.<instance-name>.retries-writing.attempts=3 (4)
artifactory.instances.<instance-name>.retries-writing.min-backoff=1s (5)
artifactory.instances.<instance-name>.retries-reading.attempts=3 (6)
artifactory.instances.<instance-name>.retries-reading.min-backoff=1s (7)
| 1 | The base path to the Artifactory instance. Defaults to /artifactory. |
| 2 | The path to the Artifactory GraphQL API. Defaults to /onemodel/api/v1/graphql. |
| 3 | The path to the Artifactory Evidence Management API. Defaults to /evidence/api/v1/subject. |
| 4 | The maximum number of retry attempts for write operations to Artifactory. Defaults to 3. |
| 5 | The minimum backoff duration between retry attempts for write operations. Defaults to 1s. |
| 6 | The maximum number of retry attempts for read operations from Artifactory. Defaults to 3. |
| 7 | The minimum backoff duration between retry attempts for read operations. Defaults to 1s. |
2.3.6. S3
To configure access to an Amazon S3 bucket for storing or reading attestations, configure the following application properties:
s3.instances.<instance-name>.region=us-east-1 (1)
s3.instances.<instance-name>.bucket-name=dpg-bucket-01 (2)
| 1 | The AWS region where the bucket is located. |
| 2 | The name of the S3 bucket. |
S3 Authentication
You can configure authentication using either static credentials, IAM roles, or environmental credentials. The application attempts to authenticate in the following order:
-
IAM Role Assumption: Used if
role-arnis configured. -
Static Credentials: Used if
access-key-idandsecret-access-keyare configured. -
Container Credentials: (Default) Uses the environment’s credentials provider chain (e.g., IRSA in EKS, EC2 instance profile).
Static Credentials:
s3.instances.<instance-name>.access-key-id=AKIA...
s3.instances.<instance-name>.secret-access-key=...
IAM Role Assumption:
s3.instances.<instance-name>.role-arn=arn:aws:iam::123456789012:role/MyRole
s3.instances.<instance-name>.role-session-name=provenance-governor
AWS IAM Permissions
The IAM Role used by the application must have the following permissions on the target S3 bucket:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::<bucket-name>",
"arn:aws:s3:::<bucket-name>/*"
]
}
]
}
-
s3:PutObject: Required for publishing attestations. -
s3:GetObject: Required for reading attestations (Fetch by ID, Policy Evaluation). -
s3:ListBucket: Required for discovering attestations during Policy Evaluation.
Associate Service Account Role (EKS)
When running on Amazon EKS, you can associate an IAM role with a Kubernetes Service Account using IRSA (IAM Roles for Service Accounts).
To enable this, the Service Account used by the Develocity Provenance Governor API pod must be annotated with the ARN of the IAM role.
The default deployment uses a Service Account named api in the develocity-provenance-governor namespace.
You can patch the Service Account after applying the manifest:
kubectl annotate serviceaccount api \
-n develocity-provenance-governor \
eks.amazonaws.com/role-arn=arn:aws:iam::123456789012:role/MyAttestationWriterRole
Alternatively, if you are using Kustomize to manage your deployment, you can create a kustomization.yaml to patch the manifest:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- manifest.yaml
patches:
- target:
kind: ServiceAccount
name: api
namespace: develocity-provenance-governor
patch: |-
- op: add
path: /metadata/annotations
value:
eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/MyAttestationWriterRole
S3 Connection Tuning
The following properties allow tuning of the S3 connection and request handling:
s3.instances.<instance-name>.endpoint=https://s3.us-west-2.amazonaws.com (1)
s3.instances.<instance-name>.path-style-access=false (2)
s3.instances.<instance-name>.max-concurrency=50 (3)
s3.instances.<instance-name>.max-object-size=10MB (4)
| 1 | The S3 endpoint URI. If omitted, the default AWS endpoint for the configured region is used. |
| 2 | Whether to use path-style access (e.g., https://s3.amazonaws.com/bucket/key). Defaults to false (virtual-hosted-style). |
| 3 | The maximum number of concurrent HTTP requests to S3. Defaults to the AWS SDK default. |
| 4 | The maximum allowed size for an attestation object. Defaults to 10MB. |
S3 Timeouts
s3.instances.<instance-name>.connection-timeout=2s (1)
s3.instances.<instance-name>.read-timeout=30s (2)
s3.instances.<instance-name>.write-timeout=30s (3)
| 1 | The timeout for establishing a connection to S3. Defaults to 2s. |
| 2 | The timeout for reading data from S3. Defaults to 30s. |
| 3 | The timeout for writing data to S3. Defaults to 30s. |
2.3.7. Signing Keys (Optional but Recommended)
Attestations are cryptographically signed using Dead Simple Signing Envelope (DSSE). Signing keys ensure attestation integrity and authenticity.
|
While signing keys are optional, they are strongly recommended for production deployments. Without signing keys:
Important: Configuring signing keys allows Develocity Provenance Governor to sign attestations. To validate those signatures during policy evaluation, you must also create a TrustedPublicKeys policy containing the public key. See the verification section below for details. |
Key Configuration in Kubernetes
Signing keys are configured in the secrets Secret using a specific naming pattern:
-
Private key:
signing.keys[0].key- The private key in PEM format (stored in Secretsecrets) -
Friendly name: Derived from timestamp or identifier you choose (e.g.,
20250818123202)
The application automatically loads private keys from the secrets Secret and extracts the corresponding public keys.
Generating Signing Keys
Develocity Provenance Governor supports three signing algorithms:
-
Ed25519 (Recommended) - 128-bit security, small key sizes, fast
-
ECDSA with prime256v1 - Elliptic curve, widely supported
-
RSA 2048 - Traditional, larger keys and signatures
Ed25519 Keys (Recommended)
Ed25519 provides the best balance of security, performance, and key size.
openssl genpkey -algorithm Ed25519 -out signing-key-20250818123202.private.pem
openssl pkey -in signing-key-20250818123202.private.pem -pubout -out signing-key-20250818123202.public.pem
Expected log message when application starts:
Signature support enabled, for key pair [name:20250818123202:keyid:b72af1:signing-algorithm:ed25519]
ECDSA Keys (Elliptic Curve)
ECDSA with the prime256v1 curve is supported by Artifactory and provides good security.
openssl ecparam -name prime256v1 -genkey -noout -out /tmp/ec_private.key
openssl pkcs8 -topk8 -inform PEM -in /tmp/ec_private.key -outform PEM -nocrypt -out signing-key-20250818123202.private.pem
openssl ec -in /tmp/ec_private.key -pubout -out signing-key-20250818123202.public.pem
Expected log message:
Signature support enabled, for key pair [name:20250818123202:keyid:a4f6cf:signing-algorithm:SHA256withECDSA]
RSA Keys
RSA 2048-bit keys are supported but produce larger signatures than Ed25519 or ECDSA.
openssl genrsa -out signing-key-20250818123202.private.pem 2048
openssl rsa -in signing-key-20250818123202.private.pem -pubout -out signing-key-20250818123202.public.pem
Expected log message:
Signature support enabled, for key pair [name:20250818123202:keyid:4a1bcb:signing-algorithm:SHA256withRSA]
Adding Keys to Kubernetes Secret
After generating keys, add the private key to the secrets Secret.
Option 1: Using stringData with application.yml
apiVersion: v1
kind: Secret
metadata:
name: secrets
namespace: develocity-provenance-governor
type: Opaque
stringData:
application.yml: |
signing:
keys:
- key: |
-----BEGIN PRIVATE KEY-----
MHcCAQEEIL...
-----END PRIVATE KEY-----
Option 2: Using individual property with base64
# Base64 encode the private key
base64 -i signing-key-20250818123202.private.pem | pbcopy
# Edit the secret
kubectl edit secret secrets --namespace develocity-provenance-governor
Add to the data: section:
data:
signing.keys[0].key: <PASTE_BASE64_PRIVATE_KEY>
|
Key Naming Convention: Use a timestamp or version identifier in your key filenames for easy rotation:
This helps track which keys are in use and when to rotate them. |
Verifying Signing Keys
After adding keys and restarting the deployment, check the logs:
kubectl rollout restart deployment/api --namespace develocity-provenance-governor
kubectl logs deployment/api --namespace develocity-provenance-governor | grep -i "Signature support"
You should see:
Signature support enabled, for key pair [name:20250818123202:keyid:b72af1:signing-algorithm:ed25519]
The keyid is a 6-character abbreviation of the SHA-256 digest of the public key, used to identify which key signed an attestation.
|
Configuring Public Keys for Attestation Validation Simply generating and configuring signing keys allows Develocity Provenance Governor to sign attestations, but does not automatically enable validation of those signatures during policy evaluation. To validate attestation signatures (including attestations published by this same instance), you must create a TrustedPublicKeys policy that includes the public key. Without a TrustedPublicKeys policy:
To enable signature validation:
Example TrustedPublicKeys Policy
This applies even when evaluating attestations published by the same Provenance Governor instance. The system treats all attestations equally and only validates signatures against explicitly trusted public keys defined in TrustedPublicKeys policies. |
Uploading Public Keys to Artifactory (Optional)
If using Artifactory for attestation storage, upload the public key to establish trust:
-
Navigate to your Artifactory instance
-
Go to Administration → Security → Key Management → Public Keys
-
Click Add Keys
-
Provide an alias (e.g.,
provenance-governor-signing-key-20250818) -
Paste the contents of
signing-key-20250818123202.public.pemor use:pbcopy < signing-key-20250818123202.public.pem -
Click Add Public Key
|
The alias in Artifactory is for human identification only and doesn’t affect functionality. The actual key matching uses the cryptographic key ID. |
2.3.8. Access Control
Access control in Develocity Provenance Governor is configured using Access Control policies, which are YAML documents formatted like the other Develocity Provenance Governor policies.
They assign access rights to identities and resources that the application has been configured with.
Develocity Provenance Governor uses a single YAML file for access control policies, but it can include multiple policies by using YAML’s --- document separator.
apiVersion: policy.gradle.com/v1
kind: AccessControl
metadata:
name: admin
spec:
identityMatchingStrategy: (1)
withBasicIdentity:
- withName: "admin" (2)
withOidc:
- withIssuerUri: https://my-oidc-issuer.example.com (3)
withClaims: (4)
organization: "my-org"
canPerform:
- publish-attestations (5)
- publish-policy-scans (6)
- read-attestations (7)
withResources: (8)
- pkg:maven/* (9)
- dv:my-develocity (10)
- af:my-artifactory/* (11)
- s3:my-s3-store/* (12)
| 1 | Matchers for identities to apply this policy to. May match OIDC (OpenID Connect) identities using HTTP Bearer auth with OIDC access tokens, or basic identities using HTTP Basic auth. |
| 2 | Matches a basic identity with the username admin. |
| 3 | Matches an OIDC identity issued by the specified issuer. |
| 4 | Restricts the OIDC matches to tokens with the specified claims. |
| 5 | Grants the ability to publish attestations. |
| 6 | Grants the ability to perform policy evaluation. |
| 7 | Grants the ability to read attestations (e.g., via Fetch Attestation by ID API). |
| 8 | Resource matchers. |
| 9 | Resource matcher that matches all maven packages. |
| 10 | Resource matcher that matches a Develocity instance named my-develocity. |
| 11 | Resource matcher that matches all repositories in the Artifactory instance named my-artifactory. |
| 12 | Resource matcher that matches all resources in the S3 instance named my-s3-store. |
While Develocity Provenance Governor uses a single YAML file for access control policies, you can include multiple policies in that file using YAML’s --- document separator.
Resources and matches
Access to resources is controlled by using resource matchers in access control policies. Matchers may match one or more resources. They are string matchers that support wildcards. The resources used are:
| Resource Type | Resource specifier |
|---|---|
Packages |
The pURL of the package.
Supports wildcards (e.g., |
Artifactory instance |
|
Develocity instance |
|
S3 instance |
|
<instance-name> matches the name you configured for the instance (e.g. my-artifactory in artifactory.instances.my-artifactory.uri).
The portion after the instance name represents the resource path relative to that instance.
For Artifactory, you can restrict access to specific repositories.
For Develocity and S3, only the wildcard /* is currently supported for the resource path.
Basic identities
Basic identities may be configured by specifying the following sensitive application property:
basic.identities.<username>=<password>
<password> uses Spring Security’s password encoder format, so you can use {noop}password for plaintext passwords, or use a password encoder such as bcrypt.
Actuator Basic Identities
To secure the Spring Boot Actuator endpoints, you can configure separate basic identities:
actuator.basic.identities.<username>=<password>
<password> uses Spring Boot’s password format, so you can use {noop}password for plaintext passwords, or use a password encoder such as bcrypt.
Password Values
The password value uses Spring Security’s format with a prefix indicating the encoding:
-
{bcrypt}$2a$10$…- Bcrypt-hashed (recommended for production) -
{noop}mypassword- Plain text (only for testing, not recommended)
To generate a bcrypt password, use:
htpasswd -bnBC 10 "" password | tr -d ':\n'
2.3.9. Policies
Develocity Provenance Governor can be configured with policies to evaluate against packages.
See Writing Policies for details on writing policies.
Develocity Provenance Governor uses a single YAML file for policies, but it can include multiple policies by using YAML’s --- document separator.
2.3.10. Signing Keys
The signing key pair must be provided through a Kubernetes secret and mounted into the api container.
|
You should have already generated your signing key pair in the Prerequisites section. This section shows how to configure Develocity Provenance Governor to use those keys. |
Step 1: Organize Your Keys
Create a directory structure for your keys with descriptive names:
mkdir -p keys/
# Copy your generated keys with a timestamp or version identifier
cp key-pair.private-pem keys/signing.key.20250818123202.private-pem
cp key-pair.public-pem keys/signing.key.20250818123202.public-pem
Your directory should look like:
keys/ signing.key.20250818123202.private-pem signing.key.20250818123202.public-pem
|
Include a timestamp or version in key filenames to support key rotation.
The pattern |
Step 2: Create the Kubernetes Secret
Create a secret from your keys directory:
kubectl create secret generic keys \
--from-file="keys/" \
--namespace develocity-provenance-governor \
--dry-run=client -o yaml > keys-secret.yaml
# Review the generated secret
cat keys-secret.yaml
# Apply the secret
kubectl apply -f keys-secret.yaml
3. Using Develocity Provenance Governor
Before using Develocity Provenance Governor, verify your installation is working:
-
Check that all pods are running:
kubectl get pods -n develocity-provenance-governor -
Verify integrations are loaded by checking logs for 'support enabled' messages:
kubectl logs deployment/api -n develocity-provenance-governor | grep "support enabled" -
Confirm authentication is working with a test request (expect 401 Unauthorized if not authenticated, or 200 if authenticated):
curl -i http://your-provenance-governor-hostname
Once verified, you can start publishing attestations and evaluating policies on software packages.
It is recommended to first start by publishing attestations for software packages. This creates the data foundation that policies will evaluate against. Once you are confident that attestations are being published correctly, you can start writing policies and evaluating them against software packages. This approach allows you to verify attestation generation is working before adding policy enforcement, reducing troubleshooting complexity.
3.1. Publishing Attestations
You can publish attestations for a software package by calling the Develocity Provenance Governor API directly, or by using the Develocity Provenance Governor GitHub Action.
In both cases, the following information will be needed:
| Information | Where to Find It | Example |
|---|---|---|
Package type |
Your build system or registry type |
|
Package name |
Artifact name from your build |
|
Package version |
Build version or tag |
|
SHA-256 digest |
Build output or registry metadata |
|
Repository URL |
Artifactory repository where package is stored |
|
Build Scan IDs or Query |
Develocity Build Scan URLs or advanced search |
|
3.1.1. When to Publish Attestations
You can publish attestations for a software package at any time after the package has been built and published to Artifactory.
This flexibility allows you to optimize your workflow:
-
Immediate publishing: Publish right after the build for complete tracking of all artifacts
-
Gated publishing: Only publish for packages that pass quality gates to reduce storage costs
-
Batch publishing: Collect multiple builds and publish attestations together for efficiency
Delaying attestations until it is known the software package will move forward in the software supply chain can help reduce the number of attestations that need to be stored and managed. For example, you may choose to only publish attestations for packages that have passed an initial quality gate.
For details on how to publish attestations using the Develocity Provenance Governor API, see _Appendix A: API Reference.
For details on how to publish attestations using the Develocity Provenance Governor GitHub Action, see GitHub Actions.
3.1.2. Attestation Types
Develocity Provenance Governor generates attestations which are compliant with the in-toto Attestations Framework. Each attestation is a JSON document wrapped in a signing envelope and has a subject and a predicate. The predicate has a type that describes the kind of attestation it is, as well as properties specific to that predicate type.
|
A more detailed description of the attestations published by Develocity Provenance Governor can be found in Appendix: Attestation Reference. |
The table below lists the types of attestations Develocity Provenance Governor can generate:
| Attestation | Predicate Type | Description |
|---|---|---|
Build Tool |
|
Attests to the build tool used to create the package, including its version. |
Java Toolchain |
|
Attests to the Java toolchain used to build the package, including the JDK version and vendor. |
Resolved Dependencies Repositories |
|
Attests to which repository resolved dependencies were fetched from when building the package. |
Resolved Dependencies |
|
Attests to the dependencies that were resolved when building the package. |
3.2. Writing Policies
Develocity Provenance Governor can evaluate policies against software packages to determine if they are compliant with your organization’s requirements. Develocity Provenance Governor uses the published attestations to evaluate policies.
|
Policies evaluate against the attestations generated by Develocity Provenance Governor. If you need to enforce requirements not covered by the current attestation types, contact support to discuss your use case. |
Develocity Provenance Governor uses declarative YAML policies instead of code-based policy languages (like Rego in Open Policy Agent). This makes policies easier to read, write, and version control alongside your deployment configuration.
3.2.1. Policy Architecture Overview
Before writing policies, it’s important to understand how the different components work together:
Example Flow:
# 1. Write a policy with a label
apiVersion: policy.gradle.com/v1
kind: JavaToolchains
metadata:
name: require-java-21
labels:
policy.my-corp.com/gate: production # <-- Label
spec:
matchingStrategy: must-match
toolchains:
- vendor: Eclipse Adoptium
versions: ["21.0.5"]
# 2. Create a PolicyScanDefinition that selects policies by label
---
apiVersion: policy.gradle.com/v1
kind: PolicyScanDefinition
metadata:
name: production-gate
spec:
description: Policies for production deployments
policy-selector:
match-labels:
policy.my-corp.com/gate: production # <-- Selects all policies with this label
# 3. Execute the scan via API (references the PolicyScanDefinition name)
# POST /packages/maven/com.example/my-app/1.0.0/policy-scans/production-gate
This architecture allows you to:
-
Write policies once and reuse them across multiple scans
-
Create different policy sets for different environments (dev, staging, production)
-
Organize policies by team, compliance requirement, or deployment stage
-
Change which policies are enforced without modifying individual policies
3.2.2. Types of policies
The table below lists the kinds of policies you can define in Develocity Provenance Governor:
| Policy Kind | Description |
|---|---|
|
Checks for the use of a specific build tool and version. Can be used to deny use of specific build tools or versions, or require the use of a specific build tool or version. |
|
Checks for the use of a specific Java toolchain (JDK version and vendor). Can be used to deny use of specific JDK versions or vendors, or require the use of a specific JDK version or vendor. |
|
Checks for the use of specific repositories to resolve dependencies. Can be used to prevent the use of specific repositories, or require the use of a specific repository. |
|
Checks for the use of specific dependencies. Can be used to prevent the use of specific dependencies, or require the use of a specific version of a dependency. |
|
Checks for the presence of specific types of attestations for a package. Can be used to ensure that required metadata (e.g., build tool info) has been captured. |
|
Checks the signatures on attestations to verify they were signed with a trusted key and that the attestation has not been tampered with. |
|
Groups multiple policies together for execution using label selectors. Used to create reusable policy scan configurations (e.g., "build-gate", "production-gate") that can be triggered via the API. |
The following sections describe each policy type in more detail, along with examples of how to write them.
3.2.3. General policy structure
All policies share a common structure.
Policies are modeled as Kubernetes-style custom resources, with apiVersion, kind, metadata, and spec properties.
|
Policies are not true Kubernetes resources, but the format makes them recognizable to those familiar with Kubernetes. |
The following snippet demonstrates the general structure used by all policies:
apiVersion: policy.gradle.com/v1
kind: TypeOfPolicy (1)
metadata: (2)
name: friendly-name (3)
labels: (4)
policy.my-corp.com/gate: build
policy.my-corp.com/owner: DevSecOps
spec:
description: Human-readable description of the policy. (5)
remediation: Human-readable remediation steps if the policy is violated. (6)
matchingStrategy: must-match or none-match (7)
resultsLabels: (8)
policy.my-corp.com/cvss: <critical|high|medium|low> # common for vulnerability management
policy.my-corp.com/severity: <minor|sever|warning> # common for compliance and regulatory enforcement / risk assessment
policy.my-corp.com/dry-run: true # domain specific
policy.my-corp.com/severity-level: <SEV-1,SEV-2,SEV-3> # common for incident management
| 1 | The kind property defines the type of policy. This will drive what properties are required in the spec property. |
| 2 | The metadata.* properties are similar to traditional Kubernetes metadata information which includes name, labels, annotations. |
| 3 | The name property is a unique identifier for the policy. |
| 4 | Policies that set metadata.labels can be selected by policy scans for inclusion if the label satisfies the selector defined. A policy can be included in multiple policy scans. See Evaluating Policies for more information. |
| 5 | The spec.description explains in human-readable terms what the policy is attesting to about a software package. |
| 6 | The spec.remediation explains in human-readable terms what will be reported back in the policy scan and what needs done to the software package to make the package compliant. |
| 7 | The spec.matchingStrategy defines how the policy values are evaluated against the attestation data:
|
| 8 | The spec.resultsLabels allows the policy author to define key value pairs to write to the policy results. See Result labels for more information. |
|
Each kind of policy defines policy-specific properties (under the |
|
You can include multiple policies in a single YAML file by separating them with |
Result labels
Result labels are useful when policies are evaluated as part of a policy scan.
The labels can be used to categorize and filter policy scan results based on severity, compliance level, or other criteria relevant to your organization’s governance processes. For example, you might use result labels to indicate the severity of a policy violation (e.g., critical, high, medium, low), the type of compliance issue (e.g., security, license, quality), or the team responsible for addressing the issue (e.g., frontend, backend, devops).
3.2.4. BuildTool
A BuildTool policy enforces which build tools are allowed or disallowed in builds. Specific tools and versions can be required or prohibited.
This policy operates on the https://gradle.com/attestation/build-tool/v1 predicate type.
kind: BuildTool
apiVersion: policy.gradle.com/v1
metadata:
name: example-build-tool-policy
labels:
policy.my-corp.com/gate: build
annotations:
createdBy: admin
spec:
resultsLabels:
policy.my-corp.com/gate: build
description: Require specific build tools and versions for CI pipelines
remediation: Use an approved build tool and version
matchingStrategy: must-match
buildTools:
- toolType: gradle
toolVersions:
- "7.6"
- "8.0"
agentVersions:
- "1.0"
- "2.0"
- toolType: maven
toolVersions:
- "3.8.6"
agentVersions:
- "1.0"
3.2.5. JavaToolchains
A JavaToolchains policy enforces which Java toolchains are allowed or disallowed in builds. Specific vendors and versions can be required or prohibited.
Scenario: Your organization has banned Oracle JDK due to licensing changes and requires all teams to use BellSoft Liberica JDK version 21.0.5 or later.
Solution: Create two policies - one to deny Oracle, one to require BellSoft:
apiVersion: policy.gradle.com/v1
kind: JavaToolchains
metadata:
name: none-match-oracle-java-toolchain
labels:
policy.my-corp.com/gate: build
spec:
resultsLabels:
policy.my-corp.com/gate: build
description: Disallow Oracle Java Toolchains in builds.
remediation: Update the Gradle build to use BellSoft Java toolchain.
matchingStrategy: none-match
toolchains:
- vendor: oracle
apiVersion: policy.gradle.com/v1
kind: JavaToolchains
metadata:
name: must-match-bellsoft-java-toolchain
labels:
policy.my-corp.com/gate: build
spec:
resultsLabels:
policy.my-corp.com/gate: build
description: Builds must use BellSoft Java toolchains in builds.
remediation: Update the build to use BellSoft Java toolchain.
matchingStrategy: must-match
toolchains:
- vendor: BellSoft Liberica
versions:
- 21.0.8
- 21.0.7
- 21.0.6
- 21.0.5
3.2.6. ResolvedDependenciesRepositories
A ResolvedDependenciesRepositories policy controls the dependency repositories which are allowed to be used to resolve and fetch dependencies.
This policy operates on the https://gradle.com/attestation/resolved-dependencies-repositories/v1 predicate type.
apiVersion: policy.gradle.com/v1
kind: ResolvedDependenciesRepositories
metadata:
name: must-match-repositories
labels:
policy.my-corp.com/gate: build
spec:
resultsLabels:
policy.my-corp.com/gate: build
description: Allow resolved dependencies repositories
remediation: Remove the offending repository from build configuration
matchingStrategy: must-match
uris:
- https://artifacts.example.com/maven2
- https://repo.example.com/artifactory/libs-release-candidates-local/
- https://plugins.gradle.org/m2/
- https://repo.example.com/artifactory/public
3.2.7. PackageUrl
A PackageUrl policy controls which dependencies are allowed or disallowed in builds. This can be used to block or require specific libraries.
This policy operates on the https://gradle.com/attestation/resolved-dependencies/v1 predicate type.
Dependencies are identified using Package URLs (pURLs), which provide a standardized way to reference software packages across different ecosystems.
Package URL Pattern Syntax
Package URLs in policies support wildcard matching using the asterisk (*) character:
| Pattern | Matches | Example |
|---|---|---|
|
Exact package, any version (e.g., |
|
|
Exact package and version |
Only |
|
Exact package, wildcard patch version |
|
|
All artifacts in namespace |
|
|
All artifacts in namespace with specific version |
|
|
All Maven artifacts |
Any Maven package |
|
All packages in npm scope |
|
|
Wildcards ( |
apiVersion: policy.gradle.com/v1
kind: PackageUrl
metadata:
name: none-match-purl-lombok
labels:
policy.my-corp.com/gate: build
spec:
resultsLabels:
policy.my-corp.com/gate: build
description: Disallow lombok dependency
remediation: Remove lombok dependency from project
matchingStrategy: none-match
purls:
- pkg:maven/org.projectlombok/lombok
apiVersion: policy.gradle.com/v1
kind: PackageUrl
metadata:
name: none-match-purl-spring-beans-6.2.7
labels:
policy.my-corp.com/gate: build
spec:
resultsLabels:
policy.my-corp.com/gate: build
description: Find usages of spring 6.2.7
remediation: Upgrade dependency to spring 6.2.7
matchingStrategy: none-match
purls:
- pkg:maven/org.springframework/*@6.2.7
apiVersion: policy.gradle.com/v1
kind: PackageUrl
metadata:
name: must-match-approved-spring-versions
labels:
policy.my-corp.com/gate: build
spec:
resultsLabels:
policy.my-corp.com/gate: build
description: Ensure only approved patch versions of Spring Framework are used.
remediation: Upgrade or downgrade to an approved patch version (e.g., 6.0.10, 6.1.5).
matchingStrategy: must-match
purls:
- pkg:maven/org.springframework/spring-core@6.0.10
- pkg:maven/org.springframework/spring-beans@6.0.10
- pkg:maven/org.springframework/spring-web@6.0.10
- pkg:maven/org.springframework/spring-core@6.1.5
- pkg:maven/org.springframework/spring-beans@6.1.5
- pkg:maven/org.springframework/spring-web@6.1.5
3.2.8. AttestationsExist
An AttestationsExist policy operates on the predicateType field of all attestations associated with a software package.
This can be used to ensure that critical metadata, regardless of its origin, has been captured and published.
Develocity Provenance Governor currently generates attestations with the following predicate types:
apiVersion: policy.gradle.com/v1
kind: AttestationsExist
metadata:
name: require-build-tool-attestation
labels:
policy.my-corp.com/gate: build
spec:
resultsLabels:
policy.my-corp.com/gate: build
description: Require Build Tool attestation to be present.
remediation: Ensure the build publishes a Build Tool attestation.
expectedPredicates:
- https://gradle.com/attestation/build-tool/v1
apiVersion: policy.gradle.com/v1
kind: AttestationsExist
metadata:
name: require-verification-summary-attestation
labels:
policy.my-corp.com/gate: production
spec:
resultsLabels:
policy.my-corp.com/gate: production
description: Require Verification Summary attestation (VSA) to be present.
remediation: Ensure the package has passed a policy scan which generates a VSA.
expectedPredicates:
- https://slsa.dev/verification_summary/v1
|
Verification Summary Attestations (VSAs) are automatically generated when a Policy Scan is executed. Requiring a VSA ensures that the package has been evaluated against a set of policies before deployment. |
3.2.9. TrustedPublicKeys
A TrustedPublicKeys policy defines which public keys are trusted for verifying attestation signatures. This policy is used to ensure that only attestations signed with approved keys are accepted during policy evaluation.
This policy operates on the attestation envelope and verifies the signature against the payload.
apiVersion: policy.gradle.com/v1
kind: TrustedPublicKeys
metadata:
name: trusted-keys
labels:
policy.my-corp.com/gate: build
spec:
description: For the Java 21 toolchain, validate attestation signatures
remediation: Make sure the attestations are signed with the expected key
keys:
my-signing-key: (1)
pem: |- (2)
-----BEGIN PUBLIC KEY-----
MCowBQYDK2VwAyEAVzZ+Xr2RqM6RvYcOmxPADdMi7u8pJ7L8Fv6HnQz/xJg=
-----END PUBLIC KEY-----
my-b64-key: (3)
pemBase64: LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUNvd0JRWURLMlZ3QXlFQVZ6WitYcjJScU02UnZZY09teFBBRGRNaTd1OHBKN0w4RnY2SG5Rei94Smc9Ci0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQo=
| 1 | A unique identifier for this key. Use a descriptive name that indicates its purpose or rotation date. |
| 2 | The public key in PEM format. Use this format when embedding the key directly in your policy file. |
| 3 | The public key in Base64-encoded PEM format. Use this format when the key is stored as a single-line string. |
The keys map allows you to specify one or more trusted public keys, either as PEM or Base64-encoded PEM.
This policy is typically referenced by label in a PolicyScanDefinition to enforce signature validation on attestations.
3.3. Evaluating Policies
Develocity Provenance Governor performs "Policy Scans" to evaluate policies against a software package. Policy Scans are defined declaratively in YAML using a PolicyScanDefinition. Policy Scan definitions are stored alongside policies.
Policy Scans execute during your CI/CD pipeline, typically:
-
After building and publishing a package
-
After attestations are published to Artifactory
-
Before promoting to the next environment
-
Before deploying to production
The scan results determine whether the pipeline proceeds or fails based on policy compliance.
When a Policy Scan is executed, Develocity Provenance Governor retrieves the relevant policies based on the label selectors defined in the PolicyScanDefinition. It then evaluates each policy against the attestations associated with the specified software package.
Policy scans help to create reusable, targeted validation strategies by grouping related policies together.
Choose a policy scan organization strategy:
| Strategy | Use When | Example Scans |
|---|---|---|
By Environment |
Different rules per deployment stage |
|
By Package Type |
Different rules per artifact type |
|
By Team |
Different teams have different rules |
|
By Compliance |
Regulatory requirements vary |
|
Most organizations combine strategies, for example: prod-backend-scan or staging-frontend-scan.
3.3.1. Verification Summary Attestation
When a Policy Scan is executed, Develocity Provenance Governor automatically generates and publishes a Verification Summary Attestation (VSA). This VSA serves as a durable, signed record that the specific artifact was verified against the specific policy at a specific time.
The VSA follows the SLSA Verification Summary v1.2 specification and provides cryptographically verifiable evidence of policy compliance.
How VSAs Are Generated
For each Policy Scan execution:
-
Policies are evaluated against the artifact’s attestations
-
Results are collected - all policy evaluation results (satisfied, unsatisfied, not-applicable)
-
VSA is created with:
-
Verification result (
PASSEDif all applicable policies satisfied,FAILEDotherwise) -
Reference to the Policy Scan Definition used
-
List of input attestations that were evaluated
-
Timestamp of verification
-
Verifier information (Develocity Provenance Governor instance)
-
-
VSA is signed using the configured signing keys
-
VSA is published to all configured attestation stores
VSA Storage and Retrieval
Where VSAs Are Stored:
The VSA is published to all attestation store instances configured for your deployment (Artifactory, S3, or both). The VSA is stored alongside the artifact’s other attestations using the same storage hierarchy.
Retrieving a VSA:
VSAs can be retrieved using the standard "Fetch Attestation by ID" endpoint:
curl --request GET \
--url https://provenance-governor.example.com/packages/maven/com.example/my-app/1.0.0/sha256:abc.../attestations/s3:prod/vsa-uuid \
--header 'authorization: Basic ***********=' \
--header 'accept: application/json'
The VSA identifier and storage location are logged during policy scan execution.
VSA Structure:
The returned VSA is a DSSE envelope containing an in-toto Statement with predicate type https://slsa.dev/verification_summary/v1. See the Verification Summary Predicate Reference for the complete structure.
VSA Signing Configuration
VSAs are signed using the same signing keys configured for other attestations. Ensure you have configured signing keys in your application configuration:
signing:
keys:
- key: |
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIL...
-----END EC PRIVATE KEY-----
Without signing keys configured, VSAs will still be generated but will not be cryptographically signed.
Failure Handling
VSA Publication Failures:
If VSA publication to any attestation store fails:
-
The error is logged but does not fail the policy scan
-
Policy scan results are still returned to the caller
-
The policy scan continues to return success/failure based on policy evaluation, not VSA publication
This design ensures that policy enforcement is not disrupted by transient storage issues.
Troubleshooting VSA Publication:
If VSAs are not being published, check:
-
Signing keys are configured - VSAs require signing keys for production use
-
Write permissions - The service account must have write access to attestation stores
-
Storage connectivity - Verify network access to S3/Artifactory instances
-
Logs - Check application logs for VSA publication errors
|
Access Control for VSA Publication
Because the Policy Scan operation now involves writing a new attestation (the VSA) to the storage, the user or service account performing the scan must have write permissions to the target repository in the Attestation Store. Ensure your |
3.3.2. PolicyScanDefinition
A PolicyScanDefinition defines a PolicyScan and selects which policies to apply using label selectors. This allows grouping and targeting of policies for specific enforcement scenarios.
apiVersion: policy.gradle.com/v1
kind: PolicyScanDefinition
metadata:
name: build-gate
labels:
policy.my-corp.com/gate: build
spec:
description: Policy scan definition for the build gate
policy-selector:
match-labels:
policy.my-corp.com/gate: build
The above policy scan will include all policies labeled with policy.my-corp.com/gate: build.
3.4. Example: Build Gate Scenario
This example demonstrates a "Build Gate" scenario, where a set of policies are applied to an artifact. The goal is to ensure that any artifact passing this gate meets specific criteria, such as being built with a trusted build tool and having the necessary attestations.
Ensure all relevant policies are labeled with policy.my-corp.com/gate: build.
For example:
apiVersion: policy.gradle.com/v1
kind: BuildTool
metadata:
name: require-gradle
labels:
policy.my-corp.com/gate: build
spec:
# ... policy details ...
Create a PolicyScanDefinition that selects these policies.
apiVersion: policy.gradle.com/v1
kind: PolicyScanDefinition
metadata:
name: build-gate
spec:
description: Validate build standards for the build gate
policy-selector:
match-labels:
policy.my-corp.com/gate: build
Trigger the policy scan via the API to validate the package against the build gate requirements:
curl --request POST \
--url https://provenance-governor.example.com/packages/maven/com.example/my-app/1.0.0/policy-scans/build-gate \
--header 'authorization: Basic ...' \
--header 'content-type: application/json' \
--data '{ ... }'
3.5. Understanding Policy Scan Results
Policy scan results provide detailed information about which policies passed or failed for a package.
The format of the response depends on the Accept header provided in the request:
-
application/json: The server collects all results and returns them as a single JSON array. This is the default behavior. -
application/x-ndjson: The server streams individual results as Newline Delimited JSON objects as soon as they are available. This is recommended for CI/CD pipelines to provide immediate feedback and prevent timeouts.
3.5.1. HTTP Status Codes
| Status Code | Meaning |
|---|---|
|
Policy scan completed. Check |
|
Invalid request (missing required fields, invalid package URL format, etc.). |
|
Authentication credentials missing or invalid. |
|
Authenticated but not authorized to scan this package. |
|
Policy scan definition not found, or package/attestations not found. |
|
Server error during policy evaluation. |
3.5.2. Interpreting Results
Successful Scan (All Policies Pass):
When all policies pass, the API will return an array where each PolicyScan.Result object has a status of satisfied or not-applicable.
[
{
"labels": {
"policy.my-corp.com/gate": "build"
},
"status": "satisfied",
"policyUri": "/policies/BuildTool/only-gradle-builds",
"policyDescription": "Ensure only Gradle is used as the build tool.",
"policyRemediation": "Use Gradle as the build tool. Consult migration guides if necessary.",
"attestationUri": "/packages/maven/com.example/my-app/1.0.0/sha256:73f482a2296dcc654c380979aae3916a1925ff906b1c43a0659f97fd56e44497/attestations/jfrog-artifactory:prod/maven-app-1.0.0-build-env",
"sourcedFromUri": "https://develocity.example.com/s/abcdef1234567",
"details": {
"buildTool": "Gradle",
"predicateType": "https://gradle.com/attestation/build-tool/v1"
}
},
{
"labels": {
"policy.my-corp.com/gate": "build"
},
"status": "satisfied",
"policyUri": "/policies/TrustedPublicKeys/release-pipeline-signer",
"policyDescription": "Verify all attestations are signed by the release pipeline's trusted key.",
"policyRemediation": "Ensure the attestation is signed by a trusted key from the release pipeline. Re-run the build if necessary.",
"attestationUri": "/packages/maven/com.example/my-app/1.0.0/sha256:73f482a2296dcc654c380979aae3916a1925ff906b1c43a0659f97fd56e44497/attestations/jfrog-artifactory:prod/maven-app-1.0.0-release",
"sourcedFromUri": null,
"details": {
"keyIds": ["abcd1234"],
"predicateType": "https://in-toto.io/Statement/v0.1"
}
}
]
Failed Scan (One or More Policies Fail):
When one or more policies fail, the API will return an array that includes PolicyScan.Result objects with a status of unsatisfied.
[
{
"labels": {
"policy.my-corp.com/gate": "build"
},
"status": "unsatisfied",
"policyUri": "/policies/ResolvedDependenciesRepositories/disallow-untrusted-repos",
"policyDescription": "Disallow untrusted Maven repositories.",
"policyRemediation": "Remove 'https://untrusted.repo.com/maven2' from your build's dependency repositories.",
"attestationUri": "/packages/maven/com.example/my-app/1.0.0/sha256:73f482a2296dcc654c380979aae3916a1925ff906b1c43a0659f97fd56e44497/attestations/jfrog-artifactory:prod/maven-app-1.0.0-build",
"sourcedFromUri": "https://develocity.example.com/s/abcdef1234567",
"details": {
"uris": ["https://untrusted.repo.com/maven2"],
"predicateType": "https://gradle.com/attestation/resolved-dependencies-repositories/v1"
}
},
{
"labels": {
"policy.my-corp.com/gate": "build"
},
"status": "satisfied",
"policyUri": "/policies/BuildTool/only-gradle-builds",
"policyDescription": "Ensure only Gradle is used as the build tool.",
"policyRemediation": "Use Gradle as the build tool. Consult migration guides if necessary.",
"attestationUri": "/packages/maven/com.example/my-app/1.0.0/sha256:73f482a2296dcc654c380979aae3916a1925ff906b1c43a0659f97fd56e44497/attestations/jfrog-artifactory:prod/maven-app-1.0.0-build-env",
"sourcedFromUri": "https://develocity.example.com/s/abcdef1234567",
"details": {
"buildTool": "Gradle",
"predicateType": "https://gradle.com/attestation/build-tool/v1"
}
}
]
3.5.3. Using Results in CI/CD
In a CI/CD pipeline, you can use application/x-ndjson to stream the API response directly into jq. This allows you to filter for any policies with an unsatisfied status as they are returned, without waiting for the entire scan to complete.
#!/bin/bash
# Stream results and filter for unsatisfied policies
# We use curl with 'Accept: application/x-ndjson' to fetch the results as a stream.
# jq filters the stream for any object where .status == "unsatisfied"
FAILED_POLICIES=$(curl -s --request POST \
--url "https://provenance-governor.example.com/packages/maven/com.example/my-app/1.0.0/policy-scans/build-gate" \
--header "authorization: Basic ${AUTH_TOKEN}" \
--header "Accept: application/x-ndjson" \
--header "content-type: application/x-www-form-urlencoded" \
--data-urlencode "sha256=a30f98e704871a244ac3f28c2ada5c120afe756e981438f221e21fff3042a11b" \
--data-urlencode "repositoryUrl=repo.example.com/docker-trial" \
| jq -c 'select(.status == "unsatisfied")')
if [ -n "$FAILED_POLICIES" ]; then
echo "Policy scan FAILED. The following policies were unsatisfied:"
echo "$FAILED_POLICIES" | jq .
exit 1
else
echo "Policy scan PASSED."
fi
|
Use the |
3.6. Integrating with Continuous Integration and Continuous Deployment systems
3.6.1. GitHub Actions
We provide GitHub Actions for easy integration with GitHub workflows.
The gradle/develocity-provenance-governor-actions/publish calls the publishing API to publish attestations for a package, and the gradle/develocity-provenance-governor-actions/enforce enforces that a policy scan passes for a package.
Both actions require a GitHub token to authenticate with the Develocity Provenance Governor API. You can base your access control policy on this token. For example:
apiVersion: policy.gradle.com/v1
kind: AccessControl
metadata:
name: example
spec:
identityMatchingStrategy:
withOidc:
- withIssuerUri: "https://token.actions.githubusercontent.com"
withClaims:
repository_owner: example-org
Example Publishing
uses: gradle/develocity-provenance-governor-actions/publish@main
with:
attestation-publisher-url: 'https://provenance-governor.example.com'
build-scan-ids: eo5xxyg3drtoc
build-scan-queries: 'value:"CI run=${{ github.run_id }}"'
subject-type: oci
subject-name: java-payment-calculator
subject-version: 1.2.3
subject-digest: 1a6b2bf83435f2a9ccd33519ad3e817bf79aee6af1c7a15d26d8a256bfa9cc94
subject-repository-url: develocitytia.jfrog.io/docker-trial
Example Enforcement
uses: gradle/develocity-provenance-governor-actions/enforce@main
with:
policy-evaluator-url: 'https://provenance-governor.example.com'
subject-type: oci
subject-name: java-payment-calculator
subject-version: 1.2.3
subject-digest: 1a6b2bf83435f2a9ccd33519ad3e817bf79aee6af1c7a15d26d8a256bfa9cc94
subject-repository-url: develocitytia.jfrog.io/docker-example-repo
policy-scan: ci-enforcement
3.6.2. Integration with Other CI/CD Systems
Develocity Provenance Governor exposes a REST API that can be used to publish attestations and evaluate policies. You can integrate with any CI/CD system that can make HTTP requests.
For example, you can use curl to publish attestations and evaluate policies from a shell script:
# Set up credentials
export DPG_URL="https://provenance-governor.example.com"
export DPG_AUTH=$(echo -n 'username:password' | base64)
# Publish attestations
curl -X POST "$DPG_URL/packages/maven/com.example/my-app/1.0.0/attestations" \
-H "Authorization: Basic $DPG_AUTH" \
-H "Content-Type: application/json" \
-d '{
"sha256": "73f482a2296dcc654c380979aae3916a1925ff906b1c43a0659f97fd56e44497",
"repositoryUrl": "artifactory.example.com/maven-repo-local",
"buildScan": {
"ids": ["bjvognekiphus"]
}
}'
See Appendix A: API Reference for complete details on the API endpoints and request/response formats, as well as example curl commands.
4. Troubleshooting
4.1. Operations
4.1.1. Updating Develocity Provenance Governor
To update to a new version:
-
Review the release notes for breaking changes and new features.
-
Update the container image in your deployment:
# Edit the deployment to use the new image version kubectl set image deployment/api api-http=registry.gradle.com/develocity/provenance-governor:NEW_VERSION@sha256:NEW_DIGEST \ -n develocity-provenance-governor # Watch the rollout kubectl rollout status deployment/api -n develocity-provenance-governor -
Verify the update:
# Check pod is running with new image kubectl get pods -n develocity-provenance-governor -o jsonpath='{.items[0].spec.containers[0].image}' # Check logs for successful startup kubectl logs deployment/api -n develocity-provenance-governor --tail=50
|
Before updating production, test the new version in a non-production environment with your existing configurations. |
4.1.2. Rolling Back to a Previous Version
If you encounter issues after an update:
-
Rollback the deployment:
kubectl rollout undo deployment/api -n develocity-provenance-governor -
Verify rollback succeeded:
kubectl rollout status deployment/api -n develocity-provenance-governor kubectl logs deployment/api -n develocity-provenance-governor --tail=50 -
Check rollout history:
kubectl rollout history deployment/api -n develocity-provenance-governor
4.1.3. Updating Configuration Without Downtime
Configuration changes (ConfigMaps, Secrets) require a pod restart to take effect:
-
Update the ConfigMap or Secret:
# For policies kubectl create configmap policies \ --from-file=policies/ \ --dry-run=client -o yaml | kubectl apply -f - # For application properties kubectl create configmap properties \ --from-file=application.properties \ --dry-run=client -o yaml | kubectl apply -f - # For secrets kubectl create secret generic secrets \ --from-file=secrets/ \ --dry-run=client -o yaml | kubectl apply -f - -
Restart the deployment:
kubectl rollout restart deployment/api -n develocity-provenance-governor kubectl rollout status deployment/api -n develocity-provenance-governor -
Verify configuration loaded:
kubectl logs deployment/api -n develocity-provenance-governor | grep "support enabled"
4.1.4. Managing Policies
Adding a new policy:
-
Add the policy YAML to your policies directory.
-
Update the policies ConfigMap.
-
Restart the deployment.
-
Verify the policy is loaded in the logs.
Disabling a policy temporarily:
Remove the labels that PolicyScanDefinitions use to select it. The policy will remain in the ConfigMap but won’t be evaluated.
Testing policy changes:
-
Create a new PolicyScanDefinition with a unique name for testing.
-
Use labels to select only the new/modified policies.
-
Test against known packages.
-
Once verified, update your production PolicyScanDefinition.
4.1.5. Backup and Restore
Backup your configuration:
# Export all configurations
kubectl get configmap policies -n develocity-provenance-governor -o yaml > policies-backup.yaml
kubectl get configmap properties -n develocity-provenance-governor -o yaml > properties-backup.yaml
kubectl get secret secrets -n develocity-provenance-governor -o yaml > secrets-backup.yaml
kubectl get secret license -n develocity-provenance-governor -o yaml > license-backup.yaml
Restore from backup:
kubectl apply -f policies-backup.yaml
kubectl apply -f properties-backup.yaml
kubectl apply -f secrets-backup.yaml
kubectl apply -f license-backup.yaml
kubectl rollout restart deployment/api -n develocity-provenance-governor
4.2. Common Issues
The following are some possible common issues, how they are recognized, and what might be needed to resolve them:
4.2.1. Invalid or missing Develocity license
The startup error clearly describes the action needed:
***************************
APPLICATION FAILED TO START
***************************
Description:
Failed to bind properties under 'develocity' to com.gradle.cavendish.dv.DevelocityProperties:
Reason: java.lang.IllegalArgumentException: No develocity.license provided in configuration.
Action:
Update your application's configuration
Ensure that the Develocity Provenance Governor deployment is configured with a valid Develocity license.
4.2.2. Missing Configuration properties
***************************
APPLICATION FAILED TO START
***************************
Description:
Failed to bind properties under 'develocity' to com.gradle.cavendish.dv.DevelocityProperties:
Reason: java.lang.IllegalArgumentException: Develocity Access Key `develocity.instances.main.access-key` must have text
Action:
Update your application's configuration
Double check to see that the property mentioned is spelled correctly and in the configuration.
4.2.3. Access control issues (403 or 401 responses)
Access control issues can be troublesome to track down as the system errors on the side of keeping sensitive information secure.
Follow these troubleshooting steps:
-
Verify your authentication is working:
kubectl logs deployment/api -n develocity-provenance-governor | grep 'Identity support enabled' -
Check that access control policies are loaded:
kubectl logs deployment/api -n develocity-provenance-governor | grep 'AccessControl' -
Verify resource matchers include trailing wildcards where needed:
-
Correct:
dv:my-instance/* -
Incorrect:
dv:my-instance(missing wildcard)
-
-
Start with a permissive policy for testing:
withResources: - "*:*/*" # Allows access to all resourcesOnce authentication is working, tighten the policy to specific resources.
-
Enable debug logging temporarily to see policy evaluation details (consult support for instructions).
4.2.4. Invalid access keys for external integrations (e.g. Develocity and Artifactory)
2025-10-16T17:51:58.967-06:00 ERROR 70284 --- [ctor-http-nio-2] c.g.c.dv.DevelocityAccessTokenManager : Error refreshing access tokens org.springframework.web.reactive.function.client.WebClientResponseException$Unauthorized: 401 Unauthorized from POST https://develocity.grdev.net/api/auth/token ...
Again, the logging should be fairly clear in this respect. The above, for example, illustrates Develocity Provenance Governor cannot communicate with Develocity. The corrective action here would be to examine the access key in the configuration that is defined for accessing Develocity and make sure it is correct.
4.2.5. Policies don’t seem to be used
2025-10-16T17:51:58.098-06:00 INFO 70284 --- [ restartedMain] c.g.c.p.PolicyScanDefinitionEvaluator : Policy Scan support enabled for [java-21-toolchain] including policy [none-match-oracle-java-toolchain] 2025-10-16T17:51:58.098-06:00 INFO 70284 --- [ restartedMain] c.g.c.p.PolicyScanDefinitionEvaluator : Policy Scan support enabled for [java-21-toolchain] including policy [must-match-bellsoft-java-toolchain] 2025-10-16T17:51:58.099-06:00 INFO 70284 --- [ restartedMain] c.g.c.p.PolicyScanDefinitionEvaluator : Policy Scan support enabled for [java-21-toolchain] including policy [purls-none-match-lombok] 2025-10-16T17:51:58.099-06:00 INFO 70284 --- [ restartedMain] c.g.c.p.PolicyScanDefinitionEvaluator : Policy Scan support enabled for [java-21-toolchain] including policy [none-match-purl-spring-beans-6.2.7] 2025-10-16T17:51:58.100-06:00 INFO 70284 --- [ restartedMain] c.g.c.p.PolicyScanDefinitionEvaluator : Policy Scan support enabled for [java-21-toolchain] including policy [must-match-repositories]
When evaluating policies, check startup logs to see which policies loaded. Each enabled policy scan logs its included policies. If your expected policy is missing:
-
Check the policy name matches exactly (case-sensitive)
-
Verify policy labels match the scan’s label selector
-
Confirm the policy YAML is in the 'policies' ConfigMap:
kubectl get configmap policies -n develocity-provenance-governor -o yaml -
Look for parsing errors in earlier log messages:
kubectl logs deployment/api -n develocity-provenance-governor | grep -i error
4.2.6. Policy Writing and Debugging
My policy doesn’t match anything
Symptoms: Policy scan shows PASSED for a none-match policy even though the forbidden item exists, or FAILED for a must-match policy even though the required item exists.
Common Causes:
-
Incorrect pURL format - Check the exact format of the dependency in attestations:
# View attestations to see exact pURL format curl -H "Authorization: Basic ..." \ "https://provenance-governor.example.com/packages/maven/com.example/my-app/1.0.0/attestations" -
Case sensitivity - Package names and vendors are case-sensitive:
-
Wrong:
pkg:maven/Org.Example/artifact -
Right:
pkg:maven/org.example/artifact
-
-
Version mismatch - If you specify a version in the pURL, it must match exactly:
-
pkg:maven/org.example/artifact@1.0.0does NOT match1.0.0-SNAPSHOT -
Use wildcards if you want to match all versions:
pkg:maven/org.example/artifact
-
-
Namespace separator - For Maven, use
/not.:-
Wrong:
pkg:maven/org.example.subpackage/artifact -
Right:
pkg:maven/org.example/subpackage-artifact
-
Understanding why a policy failed
To debug policy failures:
-
Check the policy scan results - The failure message includes which attestation values caused the failure:
{ "policyName": "must-match-java-21", "status": "FAILED", "message": "Found Java vendor: Oracle Corporation, version: 17.0.8", "remediation": "Update to Java 21" } -
Review attestation data - Compare what the policy expects vs. what’s in the attestations:
# Get all attestations for the package curl -H "Authorization: Basic ..." \ "https://provenance-governor.example.com/packages/maven/com.example/my-app/1.0.0/attestations" | jq . -
Check predicate types - Ensure your policy operates on the correct predicate type:
-
BuildTool→https://gradle.com/attestation/build-tool/v1 -
JavaToolchains→https://gradle.com/attestation/java-toolchains/v1 -
PackageUrl→https://gradle.com/attestation/resolved-dependencies/v1 -
ResolvedDependenciesRepositories→https://gradle.com/attestation/resolved-dependencies-repositories/v1 -
AttestationsExist→ Checks for presence of any predicate type (e.g.,https://slsa.dev/verification_summary/v1)
-
Policy is not being evaluated
Symptoms: Policy exists but doesn’t appear in scan results.
Troubleshooting steps:
-
Verify policy is loaded:
kubectl logs deployment/api -n develocity-provenance-governor | grep "Policy Scan support enabled" -
Check label selectors match:
Your policy must have labels that match the PolicyScanDefinition selector:
Policy:
metadata: name: my-policy labels: policy.my-corp.com/gate: buildPolicyScanDefinition:
spec: policy-selector: match-labels: policy.my-corp.com/gate: build # Must match! -
Verify YAML syntax:
# Check for YAML parsing errors kubectl get configmap policies -n develocity-provenance-governor -o yaml
Testing policies before deployment
Before deploying policies to production:
-
Start with
none-matchpolicies - These are easier to debug because they fail when unexpected items are found. -
Test against known packages - Run scans against packages you’ve already built and know the contents of.
-
Use descriptive names - Name policies clearly:
block-oracle-jdkis better thanjava-policy-1. -
Add detailed remediation - Include specific steps in the
remediationfield to help developers fix issues. -
Test both pass and fail cases - Verify the policy fails when it should and passes when it should.
4.3. Additional Help
If you experience issues with Develocity Provenance Governor or related components, please submit a support ticket at support.gradle.com, including details of the issue and an attached support bundle from Develocity, if applicable.
Appendix A: API Reference
A.1. Publish
Creates attestations from build information and published them to the attestation store.
A.1.1. Path
-
/packages/{type}/{namespace}/{name}/{version}/attestations -
/packages/{type}/{name}/{version}/attestations(when namespace is absent)
A.1.3. Produces
-
application/json(Buffered: Returns a JSON array containing all results) -
application/x-ndjson(Streaming: Returns Newline Delimited JSON objects as they become available)
A.1.4. Request Body
The request body must be a JSON object (for application/json) or form fields (for form-encoded/multipart) matching the following structure:
{
"sha256": "73f482a2296dcc654c380979aae3916a1925ff906b1c43a0659f97fd56e44497", (1)
"repositoryUrl": "artifactory.example.com/maven-repo-local", (2)
"buildScan": {
"ids": [ (3)
"1234567890aaaa",
"22222bbb"
],
"queries": [ (4)
"project:my-app value:\"CI Provider=GitHub Actions\" tag:CI tag:3.4.x"
]
}
}
| 1 | The SHA-256 hash of the package. |
| 2 | The repository the package is located in. |
| 3 | A list of Build Scan IDs to retrieve information from. Optional. |
| 4 | A list of queries to retrieve Build Scan data, using the Develocity advanced search syntax. Optional. |
A.1.5. Responses
-
200 OK: ReturnsPolicyScan.Resultobjects.-
If
Accept: application/json(default): Returns a JSON array of results. -
If
Accept: application/x-ndjson: Returns a stream of newline-delimited JSON objects.
-
-
400 Bad Request: The request content or criteria is invalid. -
401 Unauthorized: The credential information presented (if any) is not allowed access to this endpoint. -
403 Forbidden: The endpoint is accessible (authorized) but access to the resource requested is disallowed. -
500 Internal Server Error: An error occurred during attestation publishing.
A.1.6. Example Request
curl --verbose --request POST "https://provenance-governor.example.com/packages/oci/testifact/1.0/attestations" \
--header "Content-Type: application/json" \
--header "Accept: application/json, application/problem+json" \
--header "Authorization: Basic $(echo -n 'admin:password' | base64)" \
--data '
{
"sha256": "df9b564df8de07153224faa58da743ca6bc281610a6dbbec772535de19bd06e2",
"repositoryUrl": "repo.example.com/docker",
"buildScan": {
"ids": [
"bjvognekiphus"
],
"queries": [
]
}
}
curl --verbose --request POST "https://provenance-governor.example.com/packages/oci/testifact/1.0/attestations" \
--header "Content-Type: application/x-www-form-urlencoded" \
--header "Accept: application/json, application/problem+json" \
--header "Authorization: Basic $(echo -n 'admin:password' | base64)" \
--data-urlencode "sha256=df9b564df8de07153224faa58da743ca6bc281610a6dbbec772535de19bd06e2" \
--data-urlencode "repositoryUrl=repo.example.com/docker" \
--data-urlencode "buildScan.ids=bjvognekiphus"
curl --verbose --request POST "https://provenance-governor.example.com/packages/oci/testifact/1.0/attestations" \
--header "Accept: application/json, application/problem+json" \
--header "Authorization: Basic $(echo -n 'admin:password' | base64)" \
--form "sha256=df9b564df8de07153224faa58da743ca6bc281610a6dbbec772535de19bd06e2" \
--form "repositoryUrl=repo.example.com/docker" \
--form "buildScan.ids=bjvognekiphus"
curl --verbose --request POST "https://provenance-governor.example.com/packages/maven/com.example/my-maven-app/1.0.0/attestations" \
--header "Content-Type: application/json" \
--header "Accept: application/json, application/problem+json" \
--header "Authorization: Basic $(echo -n 'admin:password' | base64)" \
--data '
{
"sha256": "df9b564df8de07153224faa58da743ca6bc281610a6dbbec772535de19bd06e2",
"repositoryUrl": "https://repo.example.com/maven2",
"buildScan": {
"ids": [
"bjvognekiphus"
],
"queries": [
]
}
}
curl --verbose --request POST "https://provenance-governor.example.com/packages/maven/com.example/my-maven-app/1.0.0/attestations" \
--header "Content-Type: application/x-www-form-urlencoded" \
--header "Accept: application/json, application/problem+json" \
--header "Authorization: Basic $(echo -n 'admin:password' | base64)" \
--data-urlencode "sha256=df9b564df8de07153224faa58da743ca6bc281610a6dbbec772535de19bd06e2" \
--data-urlencode "repositoryUrl=https://repo.example.com/maven2" \
--data-urlencode "buildScan.ids=bjvognekiphus"
curl --verbose --request POST "https://provenance-governor.example.com/packages/maven/com.example/my-maven-app/1.0.0/attestations" \
--header "Accept: application/json, application/problem+json" \
--header "Authorization: Basic $(echo -n 'admin:password' | base64)" \
--form "sha256=df9b564df8de07153224faa58da743ca6bc281610a6dbbec772535de19bd06e2" \
--form "repositoryUrl=https://repo.example.com/maven2" \
--form "buildScan.ids=bjvognekiphus"
A.2. Evaluate
A.2.1. Path
-
/packages/{type}/{namespace}/{name}/{version}/policy-scans/{policy-scan-name} -
/packages/{type}/{name}/{version}/policy-scans/{policy-scan-name}(when namespace is absent)
A.2.3. Produces
-
application/json(Buffered: Returns a JSON array containing all results) -
application/x-ndjson(Streaming: Returns Newline Delimited JSON objects as they become available)
A.2.4. Request Body
The request body must be a JSON object matching the following structure:
{
"sha256": "string", (1)
"repositoryUrl": "string" (2)
}
| 1 | The SHA-256 hash of the package. |
| 2 | The repository the package is located in. |
A.2.5. Responses
Success Response
-
200 OK: ReturnsPolicyScan.Resultobjects.-
If
Accept: application/json(default): Returns a JSON array of results. -
If
Accept: application/x-ndjson: Returns a stream of newline-delimited JSON objects.
-
Error Responses
All error responses return an RFC 7807 ProblemDetail JSON object with the following structure:
-
400 Bad Request: The request content or criteria is invalid.{ "type": "about:blank", "title": "Bad Request", "status": 400, "detail": "Invalid request content. Bad criteria (sha256 or repositoryUrl)." } -
401 Unauthorized: Authentication not allowed.{ "type": "about:blank", "title": "Unauthorized", "status": 401, "detail": "Full authentication is required to access this resource" } -
403 Forbidden: Access to specific resource disallowed.{ "type": "about:blank", "title": "Forbidden", "status": 403, "detail": "Access to this resource is forbidden" } -
404 Not Found: The specified policy scan definition was not found.{ "type": "about:blank", "title": "Not Found", "status": 404, "detail": "Policy scan 'build-gate' not found" } -
429 Too Many Requests: The service is overloaded. This occurs when the connection pool is exhausted due to high concurrency.{ "type": "about:blank", "title": "Too Many Requests", "status": 429, "detail": "The service is experiencing too many requests. Please try again later." }When receiving a 429 response, implement exponential backoff retry logic. The connection pool exhaustion typically resolves within seconds as in-flight requests complete.
-
500 Internal Server Error: An error occurred communicating with an external service (Develocity, Artifactory, S3, etc.).{ "type": "about:blank", "title": "Internal Server Error", "status": 500, "detail": "An error occurred while trying to communicate with an external service: Connection refused" }
A.2.6. Example Request
curl --request POST \
--url https://provenance-governor.example.com/packages/oci/my-app/1.0.0/policy-scans/build \
--header 'authorization: Basic ***********=' \
--header 'content-type: application/json' \
--data '{
"sha256": "3f6cabfb527d740e79e0f49e2f4e564279d8c74a0bfc4481fc3a44e6b085fe91",
"repositoryUrl": "example.com/docker"
}'
curl --request POST \
--url https://provenance-governor.example.com/packages/oci/my-app/1.0.0/policy-scans/build \
--header 'authorization: Basic ***********=' \
--header 'content-type: application/x-www-form-urlencoded' \
--data-urlencode "sha256=3f6cabfb527d740e79e0f49e2f4e564279d8c74a0bfc4481fc3a44e6b085fe91" \
--data-urlencode "repositoryUrl=example.com/docker"
curl --request POST \
--url https://provenance-governor.example.com/packages/maven/com.example/my-maven-app/1.0.0/policy-scans/build \
--header 'authorization: Basic ***********=' \
--form "sha256=3f6cabfb527d740e79e0f49e2f4e564279d8c74a0bfc4481fc3a44e6b085fe91" \
--form "repositoryUrl=example.com/docker"
curl --request POST \
--url https://provenance-governor.example.com/packages/maven/com.example/my-maven-app/1.0.0/policy-scans/build \
--header 'authorization: Basic ***********=' \
--header 'content-type: application/json' \
--data '{
"sha256": "3f6cabfb527d740e79e0f49e2f4e564279d8c74a0bfc4481fc3a44e6b085fe91",
"repositoryUrl": "https://repo.example.com/maven2"
}'
curl --request POST \
--url https://provenance-governor.example.com/packages/maven/com.example/my-maven-app/1.0.0/policy-scans/build \
--header 'authorization: Basic ***********=' \
--header 'content-type: application/x-www-form-urlencoded' \
--data-urlencode "sha256=3f6cabfb527d740e79e0f49e2f4e564279d8c74a0bfc4481fc3a44e6b085fe91" \
--data-urlencode "repositoryUrl=https://repo.example.com/maven2"
curl --request POST \
--url https://provenance-governor.example.com/packages/maven/com.example/my-maven-app/1.0.0/policy-scans/build \
--header 'authorization: Basic ***********=' \
--form "sha256=3f6cabfb527d740e79e0f49e2f4e564279d8c74a0bfc4481fc3a44e6b085fe91" \
--form "repositoryUrl=https://repo.example.com/maven2"
A.2.7. Example Response
[
{
"labels": {
"policy.my-corp.com/gate": "build"
},
"status": "unsatisfied",
"policyUri": "/policies/ResolvedDependenciesRepositories/disallow-untrusted-repos",
"policyDescription": "Disallow untrusted Maven repositories.",
"policyRemediation": "Remove 'https://untrusted.repo.com/maven2' from your build's dependency repositories.",
"attestationUri": "/packages/maven/com.example/my-app/1.0.0/sha256:73f482a2296dcc654c380979aae3916a1925ff906b1c43a0659f97fd56e44497/attestations/s3:prod/uuid",
"sourcedFromUri": "https://develocity.example.com/s/abcdef1234567",
"details": {
"uris": ["https://untrusted.repo.com/maven2"]
}
},
{
"labels": {
"policy.my-corp.com/gate": "build"
},
"status": "unsatisfied",
"policyUri": "/policies/PackageUrl/disallow-vulnerable-dependency",
"policyDescription": "Disallow usage of specific vulnerable package versions.",
"policyRemediation": "Upgrade 'pkg:maven/org.example/bad-lib@1.0.0' to a non-vulnerable version (e.g., 1.0.1 or higher).",
"attestationUri": "/packages/maven/com.example/my-app/1.0.0/sha256:73f482a2296dcc654c380979aae3916a1925ff906b1c43a0659f97fd56e44497/attestations/s3:prod/uuid",
"sourcedFromUri": "https://develocity.example.com/s/abcdef1234567",
"details": {
"vulnerablePackage": "pkg:maven/org.example/bad-lib@1.0.0",
"predicateType": "https://cyclonedx.org/schema/sbom/v1.4"
}
},
{
"labels": {
"policy.my-corp.com/gate": "build"
},
"status": "satisfied",
"policyUri": "/policies/TrustedPublicKeys/release-pipeline-signer",
"policyDescription": "Verify all attestations are signed by the release pipeline's trusted key.",
"policyRemediation": "Ensure the attestation is signed by a trusted key from the release pipeline. Re-run the build if necessary.",
"attestationUri": "/packages/maven/com.example/my-app/1.0.0/sha256:73f482a2296dcc654c380979aae3916a1925ff906b1c43a0659f97fd56e44497/attestations/s3:prod/uuid",
"sourcedFromUri": null,
"details": {
"keyIds": ["abcd1234"]
}
},
{
"labels": {
"policy.my-corp.com/gate": "build"
},
"status": "not-applicable",
"policyUri": "/policies/JavaToolchains/disallow-jdk8",
"policyDescription": "Disallow Java 8 toolchains in new builds.",
"policyRemediation": "Update build configuration to use Java 11 or higher.",
"attestationUri": "/packages/maven/com.example/my-app/1.0.0/sha256:73f482a2296dcc654c380979aae3916a1925ff906b1c43a0659f97fd56e44497/attestations/s3:prod/uuid",
"sourcedFromUri": "https://develocity.example.com/s/abcdef1234567",
"details": {
"message": "Attestation does not contain 'https://gradle.com/attestation/java-toolchains/v1' predicate. Policy is not applicable."
}
},
{
"labels": {
"policy.my-corp.com/gate": "build"
},
"status": "satisfied",
"policyUri": "/policies/BuildTool/only-gradle-builds",
"policyDescription": "Ensure only Gradle is used as the build tool.",
"policyRemediation": "Use Gradle as the build tool. Consult migration guides if necessary.",
"attestationUri": "/packages/maven/com.example/my-app/1.0.0/sha256:73f482a2296dcc654c380979aae3916a1925ff906b1c43a0659f97fd56e44497/attestations/s3:prod/uuid",
"sourcedFromUri": "https://develocity.example.com/s/abcdef1234567",
"details": {
"buildTool": "Gradle"
}
}
]
|
Response Fields:
|
A.3. Fetch Attestation by ID
Retrieves a specific attestation by its unique identifier.
A.3.1. Path
-
/packages/{type}/{namespace}/{name}/{version}/{digestType}:{digest}/attestations/{instance}/{id} -
/packages/{type}/{name}/{version}/{digestType}:{digest}/attestations/{instance}/{id}(when namespace is absent)
Path Variables
-
{type}: The package type (e.g.,oci,maven) -
{namespace}: The package namespace or organization (may be omitted) -
{name}: The package name -
{version}: The package version -
{digestType}: The digest algorithm (e.g.,sha256) -
{digest}: The digest value -
{instance}: The storage instance identifier (e.g.,s3:prod-bucket,af:dev) -
{id}: The unique identifier of the attestation
|
Instance Identifier Format: The
Examples: |
A.3.2. Produces
-
application/json(Buffered: Returns a JSON array containing the attestation) -
application/x-ndjson(Streaming: Returns Newline Delimited JSON objects)
A.3.3. Responses
Error Responses
All error responses return an RFC 7807 ProblemDetail JSON object:
-
400 Bad Request: The request parameters are invalid (e.g., malformed digest, invalid instance identifier).{ "type": "about:blank", "title": "Bad Request", "status": 400, "detail": "Invalid request content. Bad criteria (sha256 or repositoryUrl)." } -
401 Unauthorized: Authentication not allowed.{ "type": "about:blank", "title": "Unauthorized", "status": 401, "detail": "Full authentication is required to access this resource" } -
403 Forbidden: Access to the resource is disallowed (user lacks read permissions for this package/repository).{ "type": "about:blank", "title": "Forbidden", "status": 403, "detail": "Access to this resource is forbidden" } -
404 Not Found: The attestation was not found (either the ID doesn’t exist or the storage instance is not configured).{ "type": "about:blank", "title": "Not Found", "status": 404, "detail": "No attestation found matching request." }
A.3.4. Example Request
curl --request GET \
--url https://provenance-governor.example.com/packages/maven/com.example/my-lib/1.0.0/sha256:abc123.../attestations/s3:prod-bucket/123e4567-e89b-12d3-a456-426614174000 \
--header 'authorization: Basic ***********=' \
--header 'accept: application/json'
A.3.5. Example Response
The response is a DSSE (Dead Simple Signing Envelope) containing the attestation.
{
"payload": "eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjEiLCJwcmVkaWNhdGVUeXBlIjoiaHR0cHM6Ly9ncmFkbGUuY29tL2F0dGVzdGF0aW9uL2J1aWxkLXRvb2wvdjEiLCJzdWJqZWN0IjpbeyJuYW1lIjoicGtnOm1hdmVuL2NvbS5leGFtcGxlL215LWxpYkAxLjAuMCIsImRpZ2VzdCI6eyJzaGEyNTYiOiJhYmMxMjMuLi4ifX1dLCJwcmVkaWNhdGUiOnsiYnVpbGRUb29sIjp7Im5hbWUiOiJHcmFkbGUiLCJ2ZXJzaW9uIjoiOC41In19fQ==", (1)
"payloadType": "application/vnd.in-toto+json", (2)
"signatures": [ (3)
{
"keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA",
"sig": "MEUCIQDx8VjW7UXqBVZFxJe9KQOPQmQr6iXzOK7/dZqN8VQG2AIgKTYDLT0Kv1X5mH0Eo7w3xA4MF7B9j3jV8H2q5YN4R0w="
}
]
}
| 1 | Base64-encoded payload: When decoded, this contains an in-toto Statement with the attestation’s predicate (e.g., build tool information, dependencies, etc.) |
| 2 | Payload type: Indicates the payload is an in-toto Statement in JSON format |
| 3 | Signatures: Cryptographic signatures verifying the attestation’s authenticity |
|
Understanding the DSSE Envelope Structure: The returned JSON is a DSSE (Dead Simple Signing Envelope) that wraps the attestation:
To extract the attestation data, decode the |
Appendix B: Attestation Reference
Develocity Provenance Governor publishes several attestations to Artifactory’s evidence store. All attestations are in-toto attestations.
The following predicate types are published, when the source Build Scan contains the relevant data:
-
Resolved Dependencies (
https://gradle.com/attestation/resolved-dependencies/v1) -
Resolved Dependencies Repositories (
https://gradle.com/attestation/resolved-dependencies-repositories/v1) -
Java Toolchains (
https://gradle.com/attestation/java-toolchains/v1) -
Verification Summary (
https://slsa.dev/verification_summary/v1)
Each section below describes the predicate payload (the JSON object found in the predicate field of an in-toto Statement whose predicateType matches the given URI).
The examples show only the predicate object (not the full in-toto Statement wrapper) for brevity.
B.1. Build Tool Predicate
Predicate Type URI: https://gradle.com/attestation/build-tool/v1
Describes the build tool that ran the build.
Fields:
-
buildId(string) - The build ID, used to identify the build scan. -
buildScanUri(URI string) - Link to the Develocity Build Scan that produced this attestation. -
toolType(string) - Build tool type. Typical values:gradle,maven(future tools may appear). -
toolVersion(string) - Version of the build tool (e.g.8.10,3.9.6, etc.). -
agentVersion(string) - Version of the Develocity build agent / plugin that captured data.
{
"buildId": "g4b7d8c1m2",
"buildScanUri": "https://develocity.example.com/s/g4b7d8c1m2",
"toolType": "gradle",
"toolVersion": "8.10",
"agentVersion": "3.17"
}
B.2. Java Toolchains Predicate
Predicate Type URI: https://gradle.com/attestation/java-toolchains/v1
Captures the Java toolchains used during the build.
Fields:
-
buildScanUri(URI string) - Link to the Build Scan. -
toolchains(array of objects) - List of observed toolchains.-
vendor(string) - Vendor identifier/name (e.g.Eclipse Adoptium,Oracle Corporation). -
versions(array of strings) - List of Java runtime versions used (e.g.17.0.8).
-
{
"buildScanUri": "https://develocity.example.com/s/g4b7d8c1m2",
"toolchains": [
{
"vendor": "Eclipse Adoptium",
"versions": [
"17.0.8"
]
}
]
}
B.3. Resolved Dependencies Repositories Predicate
Predicate Type URI: https://gradle.com/attestation/resolved-dependencies-repositories/v1
Enumerates a repository consulted for dependency resolution. A single attestation will be produced that contains multiple Uniform Resource Identifiers (URIs) for all of the repositories used in the same build.
Fields:
-
buildScanUri(URI string) - Link to the Build Scan. -
uris(List of URI string) - Repository base URIs from which dependencies were resolved.
{
"buildScanUri": "https://develocity.example.com/s/g4b7d8c1m2",
"uris": [
"https://repo1.maven.org/maven2/",
"https://repo.gradle.org/gradle/libs-releases-local/",
"https://jitpack.io/"
]
}
B.4. Resolved Dependencies Predicate
Predicate Type URI: https://gradle.com/attestation/resolved-dependencies/v1
Contains the set of resolved third-party dependencies as pURLs.
Fields:
-
buildScanUri(URI string) - Link to the Build Scan for correlation. -
purls(array of strings) - Distinct, sorted list of pURLs. May be empty.
Example (truncated list):
{
"buildScanUri": "https://develocity.example.com/s/g4b7d8c1m2",
"purls": [
"pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.17.1",
"pkg:maven/org.apache.commons/commons-lang3@3.14.0",
"pkg:npm/react@18.3.1"
]
}
B.5. Verification Summary Predicate
Predicate Type URI: https://slsa.dev/verification_summary/v1
A SLSA Verification Summary Attestation (VSA) that certifies the artifact was verified against a Develocity Provenance Governor Policy Scan.
Fields:
-
verifier(object) - Identifies the entity performing the verification (Develocity Provenance Governor). -
timeVerified(string) - Timestamp of verification (ISO 8601). -
resourceUri(string) - URI of the artifact being verified (Package URL). -
policy(object) - The policy used for verification.-
uri(string) - URI of the Policy Scan Definition. -
digest(object) - SHA-256 digest of the policy content.
-
-
inputAttestations(array of objects) - Attestations used as input for verification. -
verificationResult(string) - Result of the verification (PASSEDorFAILED).
{
"verifier": {
"id": "https://provenance-governor.example.com/packages/oci/my-app/1.0.0/policy-scans/build-gate",
"version": {
"develocity-provenance-governor": "1.2.0"
}
},
"timeVerified": "2023-10-01T12:00:00Z",
"resourceUri": "pkg:maven/com.example/test-lib@1.0.0?repository_url=repo.example.com/libs-release&sha256=725a3f94ec1af8830d0f708e7941c233d3cb981a6e943ca9aee5899cceb48383",
"policy": {
"uri": "/policies/PolicyScanDefinition/build-gate",
"digest": {
"sha256": "725a3f94ec1af8830d0f708e7941c233d3cb981a6e943ca9aee5899cceb48383"
}
},
"inputAttestations": [
{
"uri": "/packages/oci/my-app/1.0.0/sha256:1f38c1af0cc5c48fc1d60cb3eb42837ec57ede8385db3018582f7c118cbff5a5/attestations/s3:local-s3/338ec7b1-4a61-5960-8983-b8eef80d9b2b",
"digest": {
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
}
}
],
"verificationResult": "PASSED"
}