├── .github
├── CODEOWNERS
└── workflows
│ ├── artifact-cleanup.yml
│ ├── command-dispatch.yml
│ ├── main.yml
│ ├── pull-request.yml
│ ├── release.yml
│ └── run-acceptance-tests.yml
├── .gitignore
├── CHANGELOG.md
├── CODE-OF-CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── Makefile
├── README.md
├── build
└── common.mk
├── design
├── 01-nouns.md
└── 02-policy-validation.md
├── scripts
├── promote.js
├── publish_packages.sh
└── reversion.js
├── sdk
├── nodejs
│ └── policy
│ │ ├── .eslintrc.js
│ │ ├── Makefile
│ │ ├── deserialize.ts
│ │ ├── index.ts
│ │ ├── package.json
│ │ ├── policy.ts
│ │ ├── protoutil.ts
│ │ ├── proxy.ts
│ │ ├── schema.ts
│ │ ├── secret.ts
│ │ ├── server.ts
│ │ ├── tests
│ │ ├── deserialize.spec.ts
│ │ ├── pb.spec.ts
│ │ ├── policy.spec.ts
│ │ ├── proxy.spec.ts
│ │ └── util.ts
│ │ ├── tsconfig.json
│ │ └── version.ts
└── python
│ ├── .gitignore
│ ├── .pylintrc
│ ├── Makefile
│ ├── Pipfile
│ ├── lib
│ ├── pulumi_policy
│ │ ├── __init__.py
│ │ ├── deserialize.py
│ │ ├── policy.py
│ │ ├── proxy.py
│ │ ├── pulumi-plugin.json
│ │ ├── py.typed
│ │ ├── secret.py
│ │ └── version.py
│ ├── setup.py
│ └── test
│ │ ├── __init__.py
│ │ ├── test_config.py
│ │ ├── test_deserialize.py
│ │ ├── test_policy.py
│ │ └── test_proxy.py
│ └── mypy.ini
└── tests
└── integration
├── config
├── policy-pack-python
│ ├── PulumiPolicy.yaml
│ ├── __main__.py
│ └── requirements.txt
├── policy-pack
│ ├── PulumiPolicy.yaml
│ ├── index.ts
│ ├── package.json
│ └── tsconfig.json
└── program
│ ├── Pulumi.yaml
│ ├── index.ts
│ ├── package.json
│ └── tsconfig.json
├── deserialize
├── policy-pack-python
│ ├── PulumiPolicy.yaml
│ ├── __main__.py
│ └── requirements.txt
├── policy-pack
│ ├── PulumiPolicy.yaml
│ ├── index.ts
│ ├── package.json
│ └── tsconfig.json
└── program
│ ├── Pulumi.yaml
│ ├── index.ts
│ ├── package.json
│ ├── resource.ts
│ └── tsconfig.json
├── enforcementlevel
├── policy-pack-python
│ ├── PulumiPolicy.yaml
│ ├── __main__.py
│ └── requirements.txt
├── policy-pack
│ ├── PulumiPolicy.yaml
│ ├── index.ts
│ ├── package.json
│ └── tsconfig.json
└── program
│ ├── Pulumi.yaml
│ ├── index.ts
│ ├── package.json
│ └── tsconfig.json
├── go.mod
├── go.sum
├── integration_test.go
├── invalid_policy
├── policy-pack
│ ├── PulumiPolicy.yaml
│ ├── index.ts
│ ├── package.json
│ └── tsconfig.json
└── program
│ ├── Pulumi.yaml
│ ├── index.ts
│ ├── package.json
│ └── tsconfig.json
├── parent_dependencies
├── policy-pack-python
│ ├── PulumiPolicy.yaml
│ └── __main__.py
├── policy-pack
│ ├── PulumiPolicy.yaml
│ ├── index.ts
│ ├── package.json
│ └── tsconfig.json
└── program
│ ├── Pulumi.yaml
│ ├── index.ts
│ ├── package.json
│ ├── resource.ts
│ └── tsconfig.json
├── provider
├── policy-pack-python
│ ├── PulumiPolicy.yaml
│ ├── __main__.py
│ └── requirements.txt
├── policy-pack
│ ├── PulumiPolicy.yaml
│ ├── index.ts
│ ├── package.json
│ └── tsconfig.json
└── program
│ ├── Pulumi.yaml
│ ├── index.ts
│ ├── package.json
│ ├── resource.ts
│ └── tsconfig.json
├── remote_component
├── policy-pack-python
│ ├── PulumiPolicy.yaml
│ ├── __main__.py
│ └── requirements.txt
├── policy-pack
│ ├── PulumiPolicy.yaml
│ ├── index.ts
│ ├── package.json
│ └── tsconfig.json
├── program
│ ├── Pulumi.yaml
│ ├── component.ts
│ ├── index.ts
│ └── package.json
└── testcomponent
│ ├── go.mod
│ ├── go.sum
│ ├── main.go
│ ├── pulumi-resource-testcomponent
│ ├── pulumi-resource-testcomponent.cmd
│ └── pulumiTypes.go
├── resource_options
├── policy-pack-python
│ ├── PulumiPolicy.yaml
│ ├── __main__.py
│ └── requirements.txt
├── policy-pack
│ ├── PulumiPolicy.yaml
│ ├── index.ts
│ ├── package.json
│ └── tsconfig.json
└── program
│ ├── Pulumi.yaml
│ ├── index.ts
│ ├── package.json
│ ├── resource.ts
│ └── tsconfig.json
├── runtime_data
├── policy-pack-python
│ ├── PulumiPolicy.yaml
│ ├── __main__.py
│ └── requirements.txt
├── policy-pack
│ ├── PulumiPolicy.yaml
│ ├── index.ts
│ ├── package.json
│ └── tsconfig.json
└── program
│ ├── Pulumi.yaml
│ ├── index.ts
│ ├── package.json
│ ├── resource.ts
│ └── tsconfig.json
├── unknown_values
├── policy-pack-python
│ ├── PulumiPolicy.yaml
│ ├── __main__.py
│ └── requirements.txt
├── policy-pack
│ ├── PulumiPolicy.yaml
│ ├── index.ts
│ ├── package.json
│ └── tsconfig.json
└── program
│ ├── Pulumi.yaml
│ ├── index.ts
│ ├── package.json
│ └── tsconfig.json
├── validate_python_resource
├── policy-pack-python
│ ├── PulumiPolicy.yaml
│ └── __main__.py
├── policy-pack
│ ├── PulumiPolicy.yaml
│ ├── index.ts
│ ├── package.json
│ └── tsconfig.json
└── program
│ ├── .gitignore
│ ├── Pulumi.yaml
│ ├── __main__.py
│ └── requirements.txt
├── validate_resource
├── policy-pack-python
│ ├── PulumiPolicy.yaml
│ └── __main__.py
├── policy-pack
│ ├── PulumiPolicy.yaml
│ ├── index.ts
│ ├── package.json
│ └── tsconfig.json
└── program
│ ├── Pulumi.yaml
│ ├── index.ts
│ ├── package.json
│ ├── resource.ts
│ └── tsconfig.json
└── validate_stack
├── policy-pack-python
├── PulumiPolicy.yaml
└── __main__.py
├── policy-pack
├── PulumiPolicy.yaml
├── index.ts
├── package.json
└── tsconfig.json
└── program
├── Pulumi.yaml
├── index.ts
├── package.json
├── resource.ts
└── tsconfig.json
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | * @pulumi/platform
2 |
--------------------------------------------------------------------------------
/.github/workflows/artifact-cleanup.yml:
--------------------------------------------------------------------------------
1 | jobs:
2 | remove-old-artifacts:
3 | runs-on: ubuntu-latest
4 | steps:
5 | - name: Remove old artifacts
6 | uses: c-hive/gha-remove-artifacts@v1
7 | with:
8 | age: 1 month
9 | skip-tags: true
10 | name: cleanup
11 | "on":
12 | schedule:
13 | - cron: 0 1 1 * *
14 |
--------------------------------------------------------------------------------
/.github/workflows/command-dispatch.yml:
--------------------------------------------------------------------------------
1 | name: command-dispatch-for-testing
2 | on:
3 | issue_comment:
4 | types: [created, edited]
5 |
6 | jobs:
7 | command-dispatch-for-testing:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - uses: actions/checkout@v2
11 | - name: Run Build
12 | uses: peter-evans/slash-command-dispatch@v2
13 | with:
14 | token: ${{ secrets.PULUMI_BOT_TOKEN }}
15 | reaction-token: ${{ secrets.GITHUB_TOKEN }}
16 | commands: run-acceptance-tests
17 | permission: write
18 | issue-type: pull-request
19 | repository: pulumi/pulumi-policy
20 |
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | env:
2 | AWS_REGION: us-west-2
3 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
4 | GO111MODULE: "on"
5 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
6 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
7 | PROVIDER: policy
8 | PULUMI_ACCESS_TOKEN: ${{ secrets.PULUMI_ACCESS_TOKEN }}
9 | PULUMI_API: https://api.pulumi-staging.io
10 | SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
11 | PYPI_USERNAME: __token__
12 | PYPI_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
13 | VERSION: ${{ github.event.client_payload.ref }}
14 | jobs:
15 | lint:
16 | name: lint
17 | runs-on: ubuntu-latest
18 | steps:
19 | - name: Set up Go ${{ matrix.go-version }}
20 | uses: actions/setup-go@v4
21 | with:
22 | go-version: ${{ matrix.go-version }}
23 | - name: Set up Python ${{ matrix.python-version }}
24 | uses: actions/setup-python@v4
25 | with:
26 | python-version: ${{ matrix.python-version }}
27 | - name: Set up Node
28 | uses: actions/setup-node@v3
29 | with:
30 | node-version: ${{matrix.node-version}}
31 | registry-url: https://registry.npmjs.org
32 | - name: Install pipenv
33 | run: |
34 | python -m pip install --upgrade pipenv pip requests wheel urllib3 chardet
35 | - name: Install pulumictl
36 | uses: jaxxstorm/action-install-gh-release@v1.5.0
37 | with:
38 | repo: pulumi/pulumictl
39 | - name: Checkout Repo
40 | uses: actions/checkout@v2
41 | - name: Unshallow clone for tags
42 | run: git fetch --prune --unshallow --tags
43 | - name: Install Yarn
44 | run: curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version 1.13.0
45 | - name: Ensure
46 | run: |
47 | make ensure
48 | - name: Lint Node
49 | run: |
50 | cd sdk/nodejs/policy && make lint
51 | - name: Lint Python
52 | run: |
53 | cd sdk/python && make lint
54 | strategy:
55 | fail-fast: true
56 | matrix:
57 | platform: [ ubuntu-latest ]
58 | go-version: [ 1.21.x ]
59 | python-version: [ 3.9.x ]
60 | node-version: [ 18.x ]
61 | build_test_publish:
62 | name: Build, Test, and Publish
63 | runs-on: ubuntu-latest
64 | steps:
65 | - name: Checkout Repo
66 | uses: actions/checkout@v2
67 | - name: Unshallow clone for tags
68 | run: git fetch --prune --unshallow --tags
69 | - name: Install Go
70 | uses: actions/setup-go@v4
71 | with:
72 | go-version: ${{ matrix.go-version }}
73 | - name: Install pulumictl
74 | uses: jaxxstorm/action-install-gh-release@v1.5.0
75 | with:
76 | repo: pulumi/pulumictl
77 | - name: Install Pulumi CLI
78 | uses: pulumi/actions@v4
79 | with:
80 | pulumi-version: ">=3.157.0"
81 | - name: Setup Node
82 | uses: actions/setup-node@v3
83 | with:
84 | node-version: ${{matrix.node-version}}
85 | registry-url: https://registry.npmjs.org
86 | - name: Setup Python
87 | uses: actions/setup-python@v4
88 | with:
89 | python-version: ${{matrix.python-version}}
90 | - name: Install pipenv
91 | run: |
92 | python -m pip install --upgrade pipenv pip requests wheel urllib3 chardet twine
93 | - name: Ensure dependencies
94 | run: make ensure
95 | - name: Checkout Scripts Repo
96 | uses: actions/checkout@v2
97 | with:
98 | path: ci-scripts
99 | repository: pulumi/scripts
100 | - name: Configure AWS Credentials
101 | uses: aws-actions/configure-aws-credentials@v1
102 | with:
103 | aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
104 | aws-region: ${{ env.AWS_REGION }}
105 | aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
106 | role-duration-seconds: 3600
107 | role-session-name: ${{ env.PROVIDER }}@githubActions
108 | role-to-assume: ${{ secrets.AWS_CI_ROLE_ARN }}
109 | - name: Build SDK
110 | run: make only_build
111 | - name: Check worktree clean
112 | run: ./ci-scripts/ci/check-worktree-is-clean
113 | - name: Run Unit Tests
114 | run: make only_test_fast
115 | - name: Run Integration Tests
116 | run: make test_all
117 | - name: Publish
118 | run: make publish_packages
119 | - name: Trigger Docs Build
120 | run: |
121 | ./ci-scripts/ci/build-package-docs.sh "policy"
122 | env:
123 | TRAVIS: true
124 | PULUMI_BOT_GITHUB_API_TOKEN: ${{ secrets.PULUMI_BOT_TOKEN }}
125 | TRAVIS_TAG: ${{ env.VERSION }}
126 | strategy:
127 | fail-fast: true
128 | matrix:
129 | platform: [ ubuntu-latest ]
130 | go-version: [ 1.21.x ]
131 | python-version: [ 3.9.x ]
132 | node-version: [ 18.x ]
133 | name: main
134 | "on":
135 | push:
136 | branches:
137 | - main
138 | paths-ignore:
139 | - CHANGELOG.md
140 | tags-ignore:
141 | - v*
142 | - sdk/*
143 | - '**'
144 |
--------------------------------------------------------------------------------
/.github/workflows/pull-request.yml:
--------------------------------------------------------------------------------
1 | name: pull-request
2 | "on":
3 | pull_request_target:
4 |
5 | env:
6 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
7 |
8 | jobs:
9 | comment-on-pr:
10 | # We only care about commenting on a PR if the PR is from a fork
11 | if: github.event.pull_request.head.repo.full_name != github.repository
12 | runs-on: ubuntu-latest
13 | steps:
14 | - uses: actions/checkout@v2
15 | - name: Comment PR
16 | uses: thollander/actions-comment-pull-request@v2
17 | with:
18 | message: |
19 | PR is now waiting for a maintainer to run the acceptance tests. This PR will only perform build and linting.
20 | **Note for the maintainer:** To run the acceptance tests, please comment */run-acceptance-tests* on the PR
21 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
22 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | env:
2 | AWS_REGION: us-west-2
3 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
4 | GO111MODULE: "on"
5 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
6 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
7 | PROVIDER: policy
8 | PULUMI_ACCESS_TOKEN: ${{ secrets.PULUMI_ACCESS_TOKEN }}
9 | PULUMI_API: https://api.pulumi-staging.io
10 | SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
11 | PYPI_USERNAME: __token__
12 | PYPI_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
13 | VERSION: ${{ github.event.client_payload.ref }}
14 | jobs:
15 | lint:
16 | name: lint
17 | runs-on: ubuntu-latest
18 | steps:
19 | - name: Set up Go ${{ matrix.go-version }}
20 | uses: actions/setup-go@v4
21 | with:
22 | go-version: ${{ matrix.go-version }}
23 | - name: Set up Python ${{ matrix.python-version }}
24 | uses: actions/setup-python@v4
25 | with:
26 | python-version: ${{ matrix.python-version }}
27 | - name: Set up Node
28 | uses: actions/setup-node@v3
29 | with:
30 | node-version: ${{matrix.node-version}}
31 | registry-url: https://registry.npmjs.org
32 | - name: Install pipenv
33 | run: |
34 | python -m pip install --upgrade pipenv pip requests wheel urllib3 chardet
35 | - name: Install pulumictl
36 | uses: jaxxstorm/action-install-gh-release@v1.5.0
37 | with:
38 | repo: pulumi/pulumictl
39 | - name: Checkout Repo
40 | uses: actions/checkout@v2
41 | - name: Unshallow clone for tags
42 | run: git fetch --prune --unshallow --tags
43 | - name: Install Yarn
44 | run: curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version 1.13.0
45 | - name: Ensure
46 | run: |
47 | make ensure
48 | - name: Lint Node
49 | run: |
50 | cd sdk/nodejs/policy && make lint
51 | - name: Lint Python
52 | run: |
53 | cd sdk/python && make lint
54 | strategy:
55 | fail-fast: true
56 | matrix:
57 | platform: [ ubuntu-latest ]
58 | go-version: [ 1.21.x ]
59 | python-version: [ 3.9.x ]
60 | node-version: [ 18.x ]
61 | build_test_publish:
62 | name: Build, Test, and Publish
63 | runs-on: ubuntu-latest
64 | steps:
65 | - name: Checkout Repo
66 | uses: actions/checkout@v2
67 | - name: Unshallow clone for tags
68 | run: git fetch --prune --unshallow --tags
69 | - name: Install Go
70 | uses: actions/setup-go@v4
71 | with:
72 | go-version: ${{ matrix.go-version }}
73 | - name: Install pulumictl
74 | uses: jaxxstorm/action-install-gh-release@v1.5.0
75 | with:
76 | repo: pulumi/pulumictl
77 | - name: Install Pulumi CLI
78 | uses: pulumi/actions@v4
79 | with:
80 | pulumi-version: ">=3.157.0"
81 | - name: Setup Node
82 | uses: actions/setup-node@v3
83 | with:
84 | node-version: ${{matrix.node-version}}
85 | registry-url: https://registry.npmjs.org
86 | - name: Setup Python
87 | uses: actions/setup-python@v4
88 | with:
89 | python-version: ${{matrix.python-version}}
90 | - name: Install pipenv
91 | run: |
92 | python -m pip install --upgrade pipenv pip requests wheel urllib3 chardet twine
93 | - name: Ensure dependencies
94 | run: make ensure
95 | - name: Checkout Scripts Repo
96 | uses: actions/checkout@v2
97 | with:
98 | path: ci-scripts
99 | repository: pulumi/scripts
100 | - name: Build SDK
101 | run: make only_build
102 | - name: Check worktree clean
103 | run: ./ci-scripts/ci/check-worktree-is-clean
104 | - name: Run Unit Tests
105 | run: make only_test_fast
106 | - name: Run Integration Tests
107 | run: make test_all
108 | - name: Publish
109 | run: make publish_packages
110 | - name: Trigger Docs Build
111 | run: |
112 | ./ci-scripts/ci/build-package-docs.sh "policy"
113 | env:
114 | TRAVIS: true
115 | PULUMI_BOT_GITHUB_API_TOKEN: ${{ secrets.PULUMI_BOT_TOKEN }}
116 | TRAVIS_TAG: ${{ env.VERSION }}
117 | strategy:
118 | fail-fast: true
119 | matrix:
120 | platform: [ ubuntu-latest ]
121 | go-version: [ 1.21.x ]
122 | python-version: [ 3.9.x ]
123 | node-version: [ 18.x ]
124 | name: release
125 | "on":
126 | push:
127 | tags:
128 | - v*.*.*
129 |
--------------------------------------------------------------------------------
/.github/workflows/run-acceptance-tests.yml:
--------------------------------------------------------------------------------
1 | env:
2 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
3 | GO111MODULE: "on"
4 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
5 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
6 | PROVIDER: policy
7 | PULUMI_ACCESS_TOKEN: ${{ secrets.PULUMI_ACCESS_TOKEN }}
8 | PULUMI_API: https://api.pulumi-staging.io
9 | SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
10 | PR_COMMIT_SHA: ${{ github.event.client_payload.pull_request.head.sha }}
11 | jobs:
12 | comment-notification:
13 | # We only care about adding the result to the PR if it's a repository_dispatch event
14 | if: github.event_name == 'repository_dispatch'
15 | runs-on: ubuntu-latest
16 | steps:
17 | - name: Create URL to the run output
18 | id: vars
19 | run: echo run-url=https://github.com/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID >> "$GITHUB_OUTPUT"
20 | - name: Update with Result
21 | uses: peter-evans/create-or-update-comment@v1
22 | with:
23 | token: ${{ secrets.GITHUB_TOKEN }}
24 | repository: ${{ github.event.client_payload.github.payload.repository.full_name }}
25 | issue-number: ${{ github.event.client_payload.github.payload.issue.number }}
26 | body: |
27 | Please view the PR build - ${{ steps.vars.outputs.run-url }}
28 | lint:
29 | name: lint
30 | runs-on: ubuntu-latest
31 | steps:
32 | - name: Set up Go ${{ matrix.go-version }}
33 | uses: actions/setup-go@v4
34 | with:
35 | go-version: ${{ matrix.go-version }}
36 | - name: Set up Python ${{ matrix.python-version }}
37 | uses: actions/setup-python@v4
38 | with:
39 | python-version: ${{ matrix.python-version }}
40 | - name: Set up Node
41 | uses: actions/setup-node@v3
42 | with:
43 | node-version: ${{matrix.node-version}}
44 | registry-url: https://registry.npmjs.org
45 | - name: Install pipenv
46 | run: |
47 | python -m pip install --upgrade pipenv pip requests wheel urllib3 chardet
48 | - name: Install pulumictl
49 | uses: jaxxstorm/action-install-gh-release@v1.5.0
50 | with:
51 | repo: pulumi/pulumictl
52 | - name: Checkout Repo
53 | uses: actions/checkout@v2
54 | - name: Unshallow clone for tags
55 | run: git fetch --prune --unshallow --tags
56 | - name: Install Yarn
57 | run: curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version 1.13.0
58 | - name: Ensure
59 | run: |
60 | make ensure
61 | - name: Lint Node
62 | run: |
63 | cd sdk/nodejs/policy && make lint
64 | - name: Lint Python
65 | run: |
66 | cd sdk/python && make lint
67 | strategy:
68 | fail-fast: true
69 | matrix:
70 | platform: [ ubuntu-latest ]
71 | go-version: [ 1.21.x ]
72 | python-version: [ 3.9.x ]
73 | node-version: [ 18.x ]
74 | build_and_test:
75 | name: Build and Test SDK
76 | runs-on: ${{ matrix.platform }}
77 | if: github.event_name == 'repository_dispatch' || github.event.pull_request.head.repo.full_name == github.repository
78 | steps:
79 | - name: Checkout Repo
80 | uses: actions/checkout@v2
81 | with:
82 | ref: ${{ env.PR_COMMIT_SHA }}
83 | - name: Unshallow clone for tags
84 | run: git fetch --prune --unshallow --tags
85 | - name: Install Go
86 | uses: actions/setup-go@v4
87 | with:
88 | go-version: ${{ matrix.go-version }}
89 | - name: Install pulumictl
90 | uses: jaxxstorm/action-install-gh-release@v1.5.0
91 | with:
92 | repo: pulumi/pulumictl
93 | - name: Install Pulumi CLI
94 | uses: pulumi/actions@v4
95 | with:
96 | pulumi-version: ">=3.157.0"
97 | - name: Setup Node
98 | uses: actions/setup-node@v3
99 | with:
100 | node-version: ${{matrix.node-version}}
101 | registry-url: https://registry.npmjs.org
102 | - name: Setup Python
103 | uses: actions/setup-python@v4
104 | with:
105 | python-version: ${{matrix.python-version}}
106 | - name: Install pipenv
107 | run: |
108 | python -m pip install --upgrade pipenv pip requests wheel urllib3 chardet
109 | - name: Ensure dependencies
110 | run: make ensure
111 | - name: Checkout Scripts Repo
112 | uses: actions/checkout@v2
113 | with:
114 | path: ci-scripts
115 | repository: pulumi/scripts
116 | - name: Build SDK
117 | run: make only_build
118 | - name: Check worktree clean
119 | run: ./ci-scripts/ci/check-worktree-is-clean
120 | - name: Run Unit Tests
121 | run: make only_test_fast
122 | - name: Run Integration Tests
123 | run: make test_all
124 | strategy:
125 | fail-fast: true
126 | matrix:
127 | platform: [ ubuntu-latest ]
128 | go-version: [ 1.21.x ]
129 | python-version: [ 3.9.x ]
130 | node-version: [ 18.x ]
131 | name: Run Acceptance Tests from PR
132 | on:
133 | repository_dispatch:
134 | types: [run-acceptance-tests-command]
135 | pull_request:
136 | branches:
137 | - main
138 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .pulumi
2 | **/bin/
3 | **/node_modules/
4 | vendor/
5 | **/Pulumi.*.yaml
6 | **/yarn-error.log
7 | **/yarn.lock
8 | .idea
9 | **/Pipfile.lock
10 | ci-scripts
11 |
--------------------------------------------------------------------------------
/CODE-OF-CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as
6 | contributors and maintainers pledge to making participation in our project and
7 | our community a harassment-free experience for everyone, regardless of age, body
8 | size, disability, ethnicity, gender identity and expression, level of experience,
9 | education, socio-economic status, nationality, personal appearance, race,
10 | religion, or sexual identity and orientation.
11 |
12 | ## Our Standards
13 |
14 | Examples of behavior that contributes to creating a positive environment
15 | include:
16 |
17 | * Using welcoming and inclusive language
18 | * Being respectful of differing viewpoints and experiences
19 | * Gracefully accepting constructive criticism
20 | * Focusing on what is best for the community
21 | * Showing empathy towards other community members
22 |
23 | Examples of unacceptable behavior by participants include:
24 |
25 | * The use of sexualized language or imagery and unwelcome sexual attention or
26 | advances
27 | * Trolling, insulting/derogatory comments, and personal or political attacks
28 | * Public or private harassment
29 | * Publishing others' private information, such as a physical or electronic
30 | address, without explicit permission
31 | * Other conduct which could reasonably be considered inappropriate in a
32 | professional setting
33 |
34 | ## Our Responsibilities
35 |
36 | Project maintainers are responsible for clarifying the standards of acceptable
37 | behavior and are expected to take appropriate and fair corrective action in
38 | response to any instances of unacceptable behavior.
39 |
40 | Project maintainers have the right and responsibility to remove, edit, or
41 | reject comments, commits, code, wiki edits, issues, and other contributions
42 | that are not aligned to this Code of Conduct, or to ban temporarily or
43 | permanently any contributor for other behaviors that they deem inappropriate,
44 | threatening, offensive, or harmful.
45 |
46 | ## Scope
47 |
48 | This Code of Conduct applies both within project spaces and in public spaces
49 | when an individual is representing the project or its community. Examples of
50 | representing a project or community include using an official project e-mail
51 | address, posting via an official social media account, or acting as an appointed
52 | representative at an online or offline event. Representation of a project may be
53 | further defined and clarified by project maintainers.
54 |
55 | ## Enforcement
56 |
57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
58 | reported by contacting the project team at code-of-conduct@pulumi.com. All
59 | complaints will be reviewed and investigated and will result in a response that
60 | is deemed necessary and appropriate to the circumstances. The project team is
61 | obligated to maintain confidentiality with regard to the reporter of an incident.
62 | Further details of specific enforcement policies may be posted separately.
63 |
64 | Project maintainers who do not follow or enforce the Code of Conduct in good
65 | faith may face temporary or permanent repercussions as determined by other
66 | members of the project's leadership.
67 |
68 | ## Attribution
69 |
70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
72 |
73 | [homepage]: https://www.contributor-covenant.org
74 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | ## Changelog
4 |
5 | The changelog in this repo is managed manually in the `CHANGELOG.md` file.
6 | PRs with a notable change should include an entry in the `HEAD (Unreleased)`
7 | section of the file.
8 |
9 | ## Releasing
10 |
11 | To release a new version of `pulumi-policy`, update the `CHANGELOG.md` file,
12 | moving all items from the `HEAD (Unreleased)` section to a new section with
13 | the new version number. Once this is merged, a new version will be published
14 | when a tag of the form `v*.*.*` is pushed to the repo. To push the tag,
15 | ask the `@release-bot` in the internal Pulumi Slack channel `#release-ops`
16 | to do a release, for example:
17 |
18 | ```
19 | @release-bot release pulumi-policy minor
20 | ```
21 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | PROJECT_NAME := policy
2 | SUB_PROJECTS := sdk/nodejs/policy sdk/python
3 | include build/common.mk
4 |
5 | .PHONY: ensure
6 | ensure::
7 | # Golang dependencies for the integration tests.
8 | cd ./tests/integration && go mod download && go mod tidy
9 |
10 | .PHONY: publish_packages
11 | publish_packages:
12 | $(call STEP_MESSAGE)
13 | ./scripts/publish_packages.sh
14 |
15 | .PHONY: test_all
16 | test_all::
17 | cd ./tests/integration && go test . -v -timeout 30m
18 |
19 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # Pulumi Policy SDK
4 |
5 | ## Overview
6 |
7 | Define and manage policy for cloud resources deployed through Pulumi.
8 |
9 | Policy rules run during `pulumi preview` and `pulumi up`, asserting that cloud resource definitions
10 | comply with the policy immediately before they are created or updated. Policies may optionally define
11 | remediations that automatically fix policy violations rather than issue warnings.
12 |
13 | During `preview`, every rule is run on every resource, and policy violations are batched up
14 | into a final report. During the update, the first policy violation will halt the deployment.
15 |
16 | Policy violations can have enforcement levels that are **advisory**, which results in a printed
17 | warning, or **mandatory**, which results in an error after `pulumi preview` or `pulumi up` completes.
18 | The enforcement level **remediate** is stronger than both and enables automatic remediations.
19 |
20 | ## Getting Started
21 |
22 | Please see [Get Started with Policy as Code](https://www.pulumi.com/docs/get-started/crossguard/) to get
23 | started authoring and enforcing policies.
24 |
25 | ## Documentation
26 |
27 | For additional documentation, guides, best practices, and FAQs, see [Policy as Code](https://www.pulumi.com/docs/guides/crossguard/).
28 |
29 | ## Examples
30 |
31 | Looking for examples? Please refer to the [examples repo](https://github.com/pulumi/examples/tree/master/policy-packs).
32 |
33 | ## Languages
34 |
35 | Policies can be written in TypeScript/JavaScript (Node.js) or Python and can be applied to Pulumi stacks written in any language.
36 |
37 | | | Language | Status |
38 | | -- | -------- | ------ |
39 | |
| [TypeScript](./sdk/nodejs) | Stable |
40 | |
| [JavaScript](./sdk/nodejs) | Stable |
41 | |
| [Python](./sdk/python) | Preview |
42 | |
| .NET | Coming Soon |
43 | |
| Go | Coming Soon |
44 |
--------------------------------------------------------------------------------
/design/02-policy-validation.md:
--------------------------------------------------------------------------------
1 | # Policy validation API by example
2 |
3 | In this text, we'll talk generally about the sequence of API calls required to validate a resource
4 | against a bunch of policies, and to push information about validation failures to the Pulumi
5 | service. As we will see, this contains two API boundaries: the gRPC API for the analyzer API (which
6 | validates resources against the policies), and the Pulumi service API for receiving policy
7 | violations.
8 |
9 | ## Step 1: The Analyzer API
10 |
11 | The `StepGenerator`, broadly, is in charge of taking events from the running Pulumi program and
12 | turning them into goal states and operations that Pulumi is supposed to drive towards.
13 |
14 | Before any step can be executed, the goal state for the given resource must be validated against the
15 | current analyzers (in this case including a `PolicyPack`).
16 |
17 | Thus, the first API boundary we cross is the interface between the `StepGenerator` and the analyzer
18 | plugins. This section will describe this API.
19 |
20 | ### `PolicyPack` is registered
21 |
22 | The engine will lazily load the analyzer plugins as they are needed. Policies are implemented as
23 | analyzer plugins, using the `PolicyPack` abstraction. The `PolicyPack` will start a gRPC server that
24 | can respond to `Analyze(...)` RPC calls.
25 |
26 | The code looks like this:
27 |
28 | ```typescript
29 | const policies = new PolicyPack("k8s-sec-rules", {
30 | policies: [
31 | {
32 | name: "no-public-services",
33 | description: "No Kubernetes Service objects should have type `LoadBalancer`",
34 | message:
35 | "Security team requires all publicly-exposed services to go through audit and approval "
36 | tags: ["security"],
37 | enforcementLevel: "mandatory",
38 | rule: (type, svc) => {
39 | return type === "kubernetes:core/v1:Service" && svc.type === "LoadBalancer";
40 | },
41 | },
42 | ],
43 | });
44 | ```
45 |
46 | ### `Analyze(...)` is called
47 |
48 | When `RegisterResource` is called, the Pulumi engine will call the `Analyze(...)` RPC on each
49 | analyzer -- in this case, there is just one analyzer, and it contains the `PolicyPack`.
50 |
51 | The raw RPC request (i.e., beneath all the sugar) will look something like this:
52 |
53 | ```javascript
54 | // Request
55 | {
56 | Type: "kubernetes:core/v1:Service",
57 | Properties: { kind: "Service", apiVersion: "v1", ... },
58 | }
59 | ```
60 |
61 | The policy registered in the previous step will receive this property bag and validate it. In the
62 | event of a failure, we would get the following response back.
63 |
64 | ```javascript
65 | // Response: list of policy violations
66 | {
67 | Diagnostics: [{
68 | ID: "k8s-sec-rules/no-public-services",
69 | Description: "No Kubernetes Service objects should have type `LoadBalancer`",
70 | Message: "Security team requires all publicly-exposed services to go through audit and approval ",
71 | Tags: ["security"],
72 | EnforcementLevel: "mandatory", // Technically, gRPC implements this field as an enum.
73 | }],
74 | }
75 | ```
76 |
77 | Note that this response does not contain the URN of the resource. In general, analyzer plugins don’t
78 | know about URNs -- since the `StepGenerator` invoked `Analyze(...)`, it keeps track of the
79 | additional metadata needed to communicate with the Pulumi service about what resources failed.
80 |
81 | In the next section, we will see that the `StepGenerator` takes this diagnostic information and
82 | marshals it into an _event_ representing a policy violation, which the Pulumi service can
83 | understand.
84 |
85 | ## Step 2: The Pulumi service events API
86 |
87 | As we mentioned in the previous section, when the `StepGenerator` calls `Analyze(...)` on a
88 | particular goal state, it receives back only enough information to know that the goal state is
89 | invalid. To make this useful to the Pulumi service, it must now convert this response into an
90 | _event_ that contains enough information that the Pulumi service can understand it.
91 |
92 | Thus, the second API boundary we reach is the event sink boundary.
93 |
94 | ### Results of `Analyze` are turned into a policy violation event
95 |
96 | The response `Analyze` returned in the last step is converted by the `StepGenerator` into the
97 | following event. Notably, it now contains:
98 |
99 | 1. The URN of the resource that failed validation
100 | 1. The ID of the policy (taking the form `/`)
101 | 1. Information useful for printing and colorizing the message
102 |
103 | > NOTE: If there were multiple policy violations, they would be "rendered" as multiple policy
104 | > violation events, and each individually sent to the Pulumi service.
105 |
106 | ```typescript
107 | {
108 | Type: "policy-violation",
109 | Payload: {
110 | URN "",
111 | Message "No Kubernetes Service objects should have type `LoadBalancer`: " +
112 | "Security team requires all publicly-exposed services to go through audit and approval ",
113 | Color "",
114 | ID "k8s-sec-rules/no-public-services",
115 | EnforcementLevel "mandatory",
116 | Prefix "",
117 | }
118 | }
119 | ```
120 |
121 | ### Policy violation event is sent to the Pulumi service
122 |
123 | Finally, once this is converted to an event that the Pulumi service understands, it is sent to the
124 | Pulumi service.
125 |
--------------------------------------------------------------------------------
/scripts/promote.js:
--------------------------------------------------------------------------------
1 | // Copyright 2016-2018, Pulumi Corporation. All rights reserved.
2 |
3 | // This program simply reads a package.json from stdin, takes a set of arguments representing
4 | // package names, and for each one, promotes that package from a peerDependency to a real dependency.
5 |
6 | // Read the package.json from stdin.
7 | let packageJSONText = "";
8 | const readline = require("readline");
9 | const stdin = readline.createInterface({
10 | input: process.stdin,
11 | output: process.stdout,
12 | terminal: false,
13 | });
14 | stdin.on("line", function(line) {
15 | packageJSONText += `${line}\n`;
16 | });
17 | stdin.on("close", function() {
18 | // All stdin is available. Parse the JSON and move dependencies around.
19 | const packageJSON = JSON.parse(packageJSONText);
20 | for (const arg of process.argv.slice(2)) {
21 | if (!packageJSON.peerDependencies || !packageJSON.peerDependencies[arg]) {
22 | throw new Error(`No peerDependency for "${arg}" found`);
23 | }
24 |
25 | // Add this dependency.
26 | if (!packageJSON.dependencies) {
27 | packageJSON.dependencies = {};
28 | }
29 | packageJSON.dependencies[arg] = packageJSON.peerDependencies[arg];
30 |
31 | // And now delete the peer dependency.
32 | delete packageJSON.peerDependencies[arg];
33 | if (Object.keys(packageJSON.peerDependencies).length === 0) {
34 | delete packageJSON.peerDependencies;
35 | }
36 | }
37 |
38 | // Now print out the result to stdout.
39 | console.log(JSON.stringify(packageJSON, null, 4));
40 | });
41 |
--------------------------------------------------------------------------------
/scripts/publish_packages.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # publish.sh builds and publishes a release.
3 | set -o nounset -o errexit -o pipefail
4 | ROOT=$(dirname $0)/..
5 |
6 | echo "Publishing NPM packages to NPMjs.com:"
7 |
8 | # For each package, first create the package.json to publish. This must be different than the one we use for
9 | # development and testing the SDK, since we use symlinking for those workflows. Namely, we must promote the SDK
10 | # dependencies from peerDependencies that are resolved via those links, to real installable dependencies.
11 | publish() {
12 | node $(dirname $0)/promote.js ${@:2} < \
13 | ${ROOT}/sdk/nodejs/$1/bin/package.json > \
14 | ${ROOT}/sdk/nodejs/$1/bin/package.json.publish
15 | pushd ${ROOT}/sdk/nodejs/$1/bin
16 | mv package.json package.json.dev
17 | mv package.json.publish package.json
18 |
19 | NPM_TAG="dev"
20 |
21 | # If the package doesn't have a pre-release tag, use the tag of latest instead of
22 | # dev. NPM uses this tag as the default version to add, so we want it to mean
23 | # the newest released version.
24 | if [[ $(jq -r .version < package.json) != *-* ]]; then
25 | NPM_TAG="latest"
26 | fi
27 |
28 | # Now, perform the publish.
29 | npm publish -tag ${NPM_TAG}
30 | npm info 2>/dev/null
31 |
32 | # And finally restore the original package.json.
33 | mv package.json package.json.publish
34 | mv package.json.dev package.json
35 | popd
36 | }
37 |
38 | publish policy
39 |
40 | echo "Publishing Pip package to pypi.org:"
41 | twine upload \
42 | -u "${PYPI_USERNAME}" -p "${PYPI_PASSWORD}" \
43 | "${ROOT}/sdk/python/env/src/dist"/*.whl \
44 | --skip-existing \
45 |
--------------------------------------------------------------------------------
/scripts/reversion.js:
--------------------------------------------------------------------------------
1 | // Copyright 2018, Pulumi Corporation. All rights reserved.
2 |
3 | var fs = require("fs");
4 |
5 | if (process.argv.length < 4) {
6 | console.error("error: missing arguments; usage: