SBOM Observer Docs logoSBOM Observer Docs

Component Scoped Policies

Deailed input documentation for Component Scoped Policies


This reference describes the JSON payload passed to Rego, Visual Builder, and JavaScript policies. It complements the conceptual overview with field-level details so you can validate policies or mock equivalent data in tests.

For step-by-step authoring guidance, see Write and test policies.

Policy input updates in progress

We're expanding the policy input to support broader supply-chain context and lifecycle metadata.

Policy Inputs

Component scoped policies are called per component with the component and vulnerabilities fields populated.

{
  component: { ... },
  vulnerabilities: [ ... ],
  namespace: { tenantId, space }
}

Typescript types

The following type definitions describe the input the policies receive. Note that not all fields are necessarily populated.

// this is the top-level object that is passed to the policy
type PolicyInputType = {
  namespace?: Namespace;
  component?: Component;
  vulnerabilities?: Vulnerability[];
  raw?: any;
};

type Namespace = {
  tenantId: OrganizationId;
  space: string;
};


type Component = {
  id: ComponentRef;
  type: ComponentType;
  packageUrl?: string; // https://github.com/package-url/purl-spec
  name: string;
  group?: string;
  version?: string;
  supplier?: Supplier;
  manufacturer?: Supplier;
  externalReferences?: ExternalReference[];
  hashes?: Record<string, string>;
  provenance?: ComponentProvenance;
  licenses?: LicenseChoice[];
  description?: string;
  lifecycle?: ComponentLifecycle;
  annotation?: ComponentAnnotation;
  properties?: Record<string, string>;
  createdAt?: string;
  updatedAt?: string;
};

type ComponentLifecycle = {
  endOfDevelopment?: string; // date string "YYYY-MM-DD"
  endOfSupport?: string;
  endOfLife?: string;
  endOfDistribution?: string;
};

type ComponentAnnotation = {
  id: ComponentRef;
  displayName?: string;
  license?: string;
  lifecycle?: ComponentLifecycle;
  supplierId?: SupplierId;
  manufacturerId?: SupplierId;
  businessCriticality?: string; // "high" | "medium" | "low"
  internal?: boolean;
  properties?: Record<string, string>;
  notes?: string;
  tags?: string[];
  createdAt?: string;
  updatedAt?: string;
};

type Vulnerability = {
  id: VulnerabilityId;
  component: ComponentRef;
  advisoryId: string;
  severity: number;
  vendorId: string;
  epss: number;
  vex?: VulnerabilityAnalysis;
};

type ImpactAnalysisResponse =
  | "can_not_fix"
  | "will_not_fix"
  | "update"
  | "rollback"
  | "workaround_available";

type ImpactAnalysisState =
  | "resolved"
  | "resolved_with_pedigree"
  | "exploitable"
  | "in_triage"
  | "false_positive"
  | "not_affected";

type ImpactAnalysisJustification =
  | "code_not_present"
  | "code_not_reachable"
  | "requires_configuration"
  | "requires_dependency"
  | "requires_environment"
  | "protected_by_compiler"
  | "protected_at_runtime"
  | "protected_at_perimeter"
  | "protected_by_mitigating_control";


type VulnerabilityAnalysis = {
  id: VulnerabilityAnalysisId;
  vulnerability: string; // vendor id CVE-2019-1234 etc
  affects?: ComponentRef[];
  state?: ImpactAnalysisState;
  justification?: ImpactAnalysisJustification;
  response?: ImpactAnalysisResponse[];
  details?: string;
  author?: UserId;
  issueOwner?: UserId;
  attestations?: string[]; // sha256
  externalReferences?: string[]; // links etc
  published: string;
  createdAt: string;
  updatedAt: string;
};


type SupplierType = "ORGANIZATION" | "PERSON";

type Supplier = {
  id?: SupplierId;
  name: string;
  type: SupplierType;
  address?: OrganizationalPostalAddress;
  url?: string[];
  contact?: OrganizationalContact[];
  createdAt?: string;
  updatedAt?: string;
  annotation?: SupplierAnnotation;
};

type SupplierAnnotation = {
  id?: SupplierId;
  displayName?: string;
  url?: string;
  contact?: OrganizationalContact;
  address?: OrganizationalPostalAddress;
  lei?: string;
  vat?: string;
  eori?: string;
  euid?: string;
  brn?: string;
  internalId?: string;
  cpeVendor?: string;
  duns?: string;
  uei?: string;
  cage?: string;
  gln?: string;
  iso6523?: string;
  notes: string;
  properties?: Record<string, string>;
  tags?: string[];
  createdAt?: string;
  updatedAt?: string;
};

type OrganizationalContact = {
  name?: string;
  email?: string;
  phone?: string;
};

type OrganizationalPostalAddress = {
  country?: string;
  region?: string;
  locality?: string;
  postOfficeBoxNumber?: string;
  postalCode?: string;
  streetAddress?: string;
};

type ExternalReference = {
  type: ExternalReferenceType;
  url?: string;
  hashes?: Record<string, string>;
};

type License = {
  id?: string;
  name?: string;
  url?: string;
};

type LicenseChoice = {
  license?: License;
  expression?: string;
};

type ComponentProvenance = {
  attestation?: string;
  provenanceUrl?: string;
  slsaVersion?: string;
  slsaVersionUrl?: string;
  builderId?: string;
  builderName?: string;
  builderUrl?: string;
  logIndex?: number;
  logEntryUrl?: string;
  logIntegratedTime?: number;
  repository?: string;
  repositoryUrl?: string;
  repositoryDigest?: string;
  buildConfigUrl?: string;
  buildConfigPath?: string;
  invocationId?: string;
  invocationUrl?: string;
};

type ComponentRef = string;
type ComponentType = string;
type ExternalReferenceType = string;
type VulnerabilityId = string;
type VulnerabilityAnalysisId = string;
type OrganizationId = string;
type UserId = string;
type SupplierId = string;

Using Supplier data in policies

Supplier information is available via the component.supplier and component.manufacturer fields. You can write policies that:

  • Flag components from unknown or unverified suppliers
  • Enforce licensing requirements based on supplier type
  • Ensure supplier metadata completeness

Example policy check:

// Require supplier information for all components
if (!input.component.supplier) {
  return {message: "Component must have supplier information", severity: 7 };
}

// Check for specific supplier annotations
if (!input.component.supplier.annotation?.internalId) {
  return {message: "Supplier has not been assigned an internal ID", severity: 3 };
}


## Sample policy input


In the [OPA Rego Playground](https://play.openpolicyagent.org/), paste the example into the **Input** field; the same structure is provided to Visual Builder evaluations and JavaScript policies.


```json
{
  "component": {
    "id": "34c0f4772324dec6d00af7127a6f7454f655bc0d",
    "packageUrl": "pkg:npm/zod@3.21.4",
    "type": "library",
    "version": "3.21.4",
    "name": "zod",
    "licenses": [{ "license": { "name": "MIT" } }],
    "createdAt": "2023-10-30T18:28:35.757164+01:00",
    "updatedAt": "2023-10-30T18:28:35.761883+01:00"
  },
  "vulnerabilities": [
    {
      "id": "8820c737e3913979bead47ce9e309ea153e1f7d1",
      "severity": 7.5,
      "vendorId": "CVE-2023-4316",
      "epss": 0.00046,
      "vex": {
        "state": "not_affected",
        "justification": "requires_configuration"
      }
    },
    {
      "id": "a1b2c3d4e5f69780b1c2d3e4f5a67890b1c2d3e4",
      "severity": 8.8,
      "vendorId": "CVE-2023-9999",
      "epss": 0.6
    }
  ],
  "namespace": {
    "tenantId": "org-4dec6d00af7127a6",
    "space": "default"
  }
}

To mock additional variants, keep the same top-level shape and extend only the nested objects required by your use case.

Usage tips

  • Store sample input files alongside policy unit tests to avoid regressions.
  • Use vulnerabilities[].vex.state to suppress resolved findings instead of maintaining custom allowlists.
  • Scope rules to namespace.space to differentiate production, staging, and customer-dedicated namespaces.