Component-scoped input

The input a component-scoped policy receives, with TypeScript types and a sample.

This page lists the JSON input a component-scoped policy receives, whether it is built in the Visual Builder or written in Rego or JavaScript. Use it to look up a field name or to build test input. For how to write a policy, see Write and test policies; for how the index behind this input is built, see Data model fundamentals.

Top-level fields

A component-scoped policy is called once per component, with the component and vulnerabilities fields populated:

{
  component: { ... },
  vulnerabilities: [ ... ],
  namespace: { tenantId, space }
}
Policy input
NamespacetenantId, space
Componentpurl, version, licenses, lifecycle, externalReferences
Vulnerability[]severity, EPSS
Supplieralso as manufacturer
ComponentAnnotationuser-edited: criticality, lifecycle
ComponentProvenanceSLSA builder, repository
VulnerabilityAnalysisstate, justification

TypeScript types

Below is the input as TypeScript types. Not every field is set on every input, so check for missing values in a policy.

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

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;
  lifecycle?: ComponentLifecycle;
  supplier?: Supplier;
  manufacturer?: Supplier;
  externalReferences?: ExternalReference[];
  hashes?: Record<string, string>;
  provenance?: ComponentProvenance;
  licenses?: LicenseChoice[];
  modelCard?: ModelCard;
  scope?: Scope;
  isExternal?: boolean;
  versionRange?: string;
  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?: BusinessCriticality;
  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 BusinessCriticality = "high" | "medium" | "low";
type ModelCard = Record<string, any>;
type Scope = 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;

Sample policy input

To test a Rego policy, paste this into the Input field of the Rego Playground. Visual Builder and JavaScript policies receive the same structure.

{
  "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 test another case, keep the top-level component, vulnerabilities, and namespace keys and change the objects under them.

Use vulnerabilities[].vex.state to skip vulnerabilities that a VEX analysis marks not_affected, false_positive, resolved, or resolved_with_pedigree, instead of keeping an allowlist in the policy.