CircleCI Field Guide
GitHub Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage
Edit page

Restricting Common Config File Keys

Individual Key Restriction

This is a policy that enforces a rule on the keys in the following config file individually and is intentionally verbose to show how to create a rule for those keys.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
package org

import future.keywords
import data.circleci.config

policy_name["project_lock"]

target_node_image = "cimg/node:19.7.0"

# enables the rule only for the setup workflow
enable_hard["check_project_config"] { input.setup == true }

check_project_config[reason] {
    # check the case where version is not in the input
    not input.version
    reason := "version must be defined"
} {
    # check that version is number
    not is_number(input.version)
    reason := "version must be a number"
} {
    # check that version is at least 2.1
    not input.version >= 2.1
    reason := sprintf("version must be at least 2.1 but got %q", [input.version])
}{
    # check that setup is true
    not input.setup
    reason := "setup must be true"
} {
    # check that only circleci orbs are used
    some orb, _ in config.orbs
    not startswith(orb, "circleci/")
    reason := sprintf("%q is not an approved orb", [orb])
} {
    # Check that cimg/node image is used
    object.get(input, ["jobs", "setup", "docker", 0, "image"], "") != "cimg/node:19.7.0"
    reason := sprintf("job %q must use image %q", ["setup", target_node_image])
} {
    # Check that small resource class is used
    resource_class := object.get(input, ["jobs", "setup", "resource_class"], "")
    resource_class != "small"
    reason := sprintf("job %q must use resource_class %q but got %q", ["setup", "small", resource_class])
} {
    # Check that the setup job contains only the expected steps
    steps := object.get(input, ["jobs", "setup", "steps"], [])
    expected_steps := [
        "checkout", 
        {"node/install-packages": {"app-dir": ".circleci/generated"}},
        {"run": "node .circleci/generated/generated.index.js"},
        {"continuation/continue": {"configuration_path": "basic_workflow.yml"}},
    ]
    steps != expected_steps
    reason := sprintf("setup steps must be %v", [expected_steps])
} {
    # Check that the workflow only contains expected jobs
    workflow := object.get(input, ["workflows"], "")
    expected_workflow := {"setup-workflow": {"jobs": ["setup"]}}
    workflow != expected_workflow
    reason := sprintf("workflow must be %q but got %q", [expected_workflow, workflow])
}

Example Config File

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
version: 2.1

setup: true

orbs:
  continuation: circleci/continuation@0.2.0
  node: circleci/node@5.1.0

jobs:
  setup:
    docker: 
      - image: cimg/node:19.7.0
    resource_class: small
    steps:
      - checkout
      - node/install-packages:
          app-dir: .circleci/generated
      - run: node .circleci/generated/generated.index.js
      - continuation/continue:
          configuration_path: basic_workflow.yml

workflows:
  setup-workflow:
    jobs:
      - setup

Common Use Cases

Documentation