├── assets ├── terraform-changes.png └── plan-output-job-summary.png ├── test-data ├── tf_noresources.json ├── tf_nochanges.json └── tf_test4.json ├── .github └── workflows │ ├── conventional-commits.yml │ ├── release.yml │ ├── reusable-terraform-test.yml │ ├── codeql-analysis.yml │ └── action-test.yml ├── catalog-info.yaml ├── package.json ├── action.yml ├── .gitignore ├── README.md ├── CHANGELOG.md ├── LICENSE ├── index.js └── dist └── licenses.txt /assets/terraform-changes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liatrio/terraform-change-pr-commenter/HEAD/assets/terraform-changes.png -------------------------------------------------------------------------------- /assets/plan-output-job-summary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liatrio/terraform-change-pr-commenter/HEAD/assets/plan-output-job-summary.png -------------------------------------------------------------------------------- /test-data/tf_noresources.json: -------------------------------------------------------------------------------- 1 | { 2 | "format_version": "1.2", 3 | "terraform_version": "1.10.5", 4 | "planned_values": { 5 | "root_module": {} 6 | }, 7 | "configuration": { 8 | "root_module": {} 9 | }, 10 | "timestamp": "2025-05-15T22:58:52Z", 11 | "applyable": false, 12 | "complete": true, 13 | "errored": false 14 | } 15 | -------------------------------------------------------------------------------- /.github/workflows/conventional-commits.yml: -------------------------------------------------------------------------------- 1 | name: Conventional Commits 2 | 3 | on: 4 | pull_request: 5 | types: 6 | - opened 7 | - edited 8 | - synchronize 9 | 10 | jobs: 11 | validate: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: liatrio/github-actions/conventional-pr-title@master 15 | with: 16 | token: ${{ secrets.GITHUB_TOKEN }} -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | on: 3 | push: 4 | branches: [main] 5 | release: 6 | types: [published] 7 | jobs: 8 | release: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v4 12 | - uses: actions/setup-node@v4 13 | with: 14 | node-version: "20" 15 | 16 | - name: Install Dependencies 17 | run: yarn install 18 | 19 | - name: yarn build and semantic-release 20 | run: yarn run build && npx semantic-release 21 | env: 22 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 23 | -------------------------------------------------------------------------------- /.github/workflows/reusable-terraform-test.yml: -------------------------------------------------------------------------------- 1 | name: Reusable Terraform Test Workflow 2 | 3 | permissions: 4 | contents: read 5 | pull-requests: write 6 | 7 | on: 8 | workflow_call: 9 | inputs: 10 | test-mode: 11 | description: 'Test mode for reusable workflow' 12 | required: false 13 | type: string 14 | default: 'reusable' 15 | 16 | jobs: 17 | reusable-test: 18 | runs-on: ubuntu-latest 19 | steps: 20 | - uses: actions/checkout@v4 21 | - uses: actions/setup-node@v4 22 | with: 23 | node-version: "20" 24 | - run: yarn install 25 | - run: yarn run build 26 | 27 | - name: Test PR Commenter via workflow_call 28 | uses: ./ 29 | with: 30 | json-file: test-data/tf_test.json 31 | comment-header: "Terraform Plan via Reusable Workflow (workflow_call event)" 32 | expand-comment: "true" 33 | include-workflow-link: "true" 34 | include-job-link: "true" -------------------------------------------------------------------------------- /catalog-info.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: backstage.io/v1alpha1 2 | kind: Component 3 | metadata: 4 | # Component names should be simple and URL-friendly 5 | name: terraform-change-pr-commenter 6 | description: >- 7 | GitHub Action that parses Terraform plan JSON files, summarizes the changes, 8 | and posts concise comments (and optional workflow summaries) to pull requests. 9 | 10 | # Annotations — see https://backstage.io/docs/features/software-catalog/well-known-annotations 11 | annotations: 12 | github.com/project-slug: liatrio/terraform-change-pr-commenter 13 | 14 | tags: 15 | - javascript 16 | - terraform 17 | - github-action 18 | - ci 19 | - iac 20 | 21 | links: 22 | - url: https://github.com/liatrio/terraform-change-pr-commenter 23 | title: Source Repository 24 | icon: github 25 | - url: https://github.com/marketplace/actions/terraform-change-pr-commenter 26 | title: GitHub Marketplace Listing 27 | icon: marketplace 28 | 29 | 30 | spec: 31 | # component category, e.g. service, library, tool, website … 32 | type: library 33 | # Review lifecycle and pick one of the three that make the most sense. 34 | # https://backstage.io/docs/features/software-catalog/descriptor-format/#speclifecycle-required 35 | lifecycle: production 36 | owner: platform-engineering 37 | system: developer-platform 38 | dependsOn: [] 39 | consumesApis: [] 40 | providesApis: [] 41 | 42 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "terraform-change-pr-commenter", 3 | "version": "1.14.0", 4 | "description": "GitHub Action to read changes from Terraform plan JSON, summarize changes, and post them in a GitHub Pull Request Comment", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "ncc build index.js --out dist --license licenses.txt", 8 | "semantic-release": "semantic-release" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "https://github.com/liatrio/terraform-change-pr-commenter.git" 13 | }, 14 | "engines": { 15 | "node": "20" 16 | }, 17 | "release": { 18 | "branches": [ 19 | "main" 20 | ], 21 | "plugins": [ 22 | "@semantic-release/commit-analyzer", 23 | "@semantic-release/release-notes-generator", 24 | "@semantic-release/changelog", 25 | [ 26 | "@semantic-release/npm", 27 | { 28 | "npmPublish": false 29 | } 30 | ], 31 | [ 32 | "@semantic-release/git", 33 | { 34 | "assets": [ 35 | "package.json", 36 | "yarn.lock", 37 | "dist", 38 | "CHANGELOG.md", 39 | "README.md" 40 | ], 41 | "message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}" 42 | } 43 | ], 44 | "@semantic-release/github" 45 | ] 46 | }, 47 | "keywords": [], 48 | "author": "Liatrio", 49 | "license": "Apache-2.0", 50 | "bugs": { 51 | "url": "https://github.com/liatrio/terraform-change-pr-commenter/issues" 52 | }, 53 | "homepage": "https://github.com/liatrio/terraform-change-pr-commenter#readme", 54 | "devDependencies": { 55 | "@semantic-release/changelog": "^6.0.1", 56 | "@semantic-release/git": "^10.0.1", 57 | "@vercel/ncc": "^0.33.1", 58 | "semantic-release": "^24.2.6" 59 | }, 60 | "dependencies": { 61 | "@actions/core": "^1.9.1", 62 | "@actions/github": "^5.0.0" 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | name: Terraform Change PR Commenter v2 2 | description: Parse changes from Terraform Plan JSON and post them for PR review 3 | branding: 4 | icon: "git-pull-request" 5 | color: "green" 6 | inputs: 7 | json-file: 8 | description: File location for the Terraform Plan JSON file 9 | required: false 10 | default: tfplan.json 11 | github-token: 12 | description: GitHub Token 13 | required: false 14 | default: "${{github.token}}" 15 | expand-comment: 16 | description: If true, expand the details comment by default 17 | required: false 18 | default: "false" 19 | include-plan-job-summary: 20 | description: If true, add the results of the plan to the workflow job summary 21 | required: false 22 | default: "false" 23 | comment-header: 24 | description: Header to use for the comment 25 | required: false 26 | default: "Terraform Plan Changes" 27 | comment-footer: 28 | description: Footer to use for the comment 29 | required: false 30 | default: "" 31 | include-workflow-link: 32 | description: If true, include a link to the workflow in the comment 33 | required: false 34 | default: "false" 35 | include-job-link: 36 | description: If true, include a link to the job run in the comment 37 | required: false 38 | default: "false" 39 | quiet: 40 | description: Skips the comment if there are no changes 41 | required: false 42 | default: "false" 43 | hide-previous-comments: 44 | description: Hides privious comments on the PR 45 | required: false 46 | default: "false" 47 | log-changed-resources: 48 | description: Log the changed resources in action output 49 | required: false 50 | default: "true" 51 | include-tag-only-resources: 52 | description: If true, include resources with only tag changes as a separate section 53 | required: false 54 | default: "false" 55 | include-unchanged-resources: 56 | description: If true, include unchanged resources in the output 57 | required: false 58 | default: "false" 59 | runs: 60 | using: node20 61 | main: dist/index.js 62 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # dist release output 2 | dist 3 | 4 | # Logs 5 | logs 6 | *.log 7 | npm-debug.log* 8 | yarn-debug.log* 9 | yarn-error.log* 10 | lerna-debug.log* 11 | 12 | # Diagnostic reports (https://nodejs.org/api/report.html) 13 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 14 | 15 | # Runtime data 16 | pids 17 | *.pid 18 | *.seed 19 | *.pid.lock 20 | 21 | # Directory for instrumented libs generated by jscoverage/JSCover 22 | lib-cov 23 | 24 | # Coverage directory used by tools like istanbul 25 | coverage 26 | *.lcov 27 | 28 | # nyc test coverage 29 | .nyc_output 30 | 31 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 32 | .grunt 33 | 34 | # Bower dependency directory (https://bower.io/) 35 | bower_components 36 | 37 | # node-waf configuration 38 | .lock-wscript 39 | 40 | # Compiled binary addons (https://nodejs.org/api/addons.html) 41 | build/Release 42 | 43 | # Dependency directories 44 | node_modules/ 45 | jspm_packages/ 46 | 47 | # TypeScript v1 declaration files 48 | typings/ 49 | 50 | # TypeScript cache 51 | *.tsbuildinfo 52 | 53 | # Optional npm cache directory 54 | .npm 55 | 56 | # Optional eslint cache 57 | .eslintcache 58 | 59 | # Microbundle cache 60 | .rpt2_cache/ 61 | .rts2_cache_cjs/ 62 | .rts2_cache_es/ 63 | .rts2_cache_umd/ 64 | 65 | # Optional REPL history 66 | .node_repl_history 67 | 68 | # Output of 'npm pack' 69 | *.tgz 70 | 71 | # Yarn Integrity file 72 | .yarn-integrity 73 | 74 | # dotenv environment variables file 75 | .env 76 | .env.test 77 | 78 | # parcel-bundler cache (https://parceljs.org/) 79 | .cache 80 | 81 | # Next.js build output 82 | .next 83 | 84 | # Nuxt.js build / generate output 85 | .nuxt 86 | 87 | # Gatsby files 88 | .cache/ 89 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 90 | # https://nextjs.org/blog/next-9-1#public-directory-support 91 | # public 92 | 93 | # vuepress build output 94 | .vuepress/dist 95 | 96 | # Serverless directories 97 | .serverless/ 98 | 99 | # FuseBox cache 100 | .fusebox/ 101 | 102 | # DynamoDB Local files 103 | .dynamodb/ 104 | 105 | # TernJS port file 106 | .tern-port 107 | 108 | .DS_Store 109 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ main ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ main ] 20 | schedule: 21 | - cron: '18 6 * * 6' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'javascript', 'actions' ] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 37 | # CodeQL also supports 'actions' for GitHub Actions 38 | # Learn more about CodeQL language support at https://git.io/codeql-language-support 39 | 40 | steps: 41 | - name: Checkout repository 42 | uses: actions/checkout@v4 43 | 44 | # Initializes the CodeQL tools for scanning. 45 | - name: Initialize CodeQL 46 | uses: github/codeql-action/init@v3 47 | with: 48 | languages: ${{ matrix.language }} 49 | # If you wish to specify custom queries, you can do so here or in a config file. 50 | # By default, queries listed here will override any specified in a config file. 51 | # Prefix the list here with "+" to use these queries and those in the config file. 52 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 53 | 54 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 55 | # If this step fails, then you should remove it and run the build manually (see below) 56 | - name: Autobuild 57 | uses: github/codeql-action/autobuild@v3 58 | 59 | # ℹ️ Command-line programs to run using the OS shell. 60 | # 📚 https://git.io/JvXDl 61 | 62 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 63 | # and modify them (or add more) to build your code if your project 64 | # uses a compiled language 65 | 66 | #- run: | 67 | # make bootstrap 68 | # make release 69 | 70 | - name: Perform CodeQL Analysis 71 | uses: github/codeql-action/analyze@v3 72 | -------------------------------------------------------------------------------- /.github/workflows/action-test.yml: -------------------------------------------------------------------------------- 1 | name: Action Tester Workflow 2 | 3 | on: 4 | pull_request: 5 | pull_request_target: 6 | workflow_call: 7 | inputs: 8 | test-mode: 9 | description: 'Test mode for workflow_call testing' 10 | required: false 11 | type: string 12 | default: 'reusable' 13 | 14 | permissions: 15 | contents: read 16 | pull-requests: write 17 | 18 | jobs: 19 | plan: 20 | runs-on: ubuntu-latest 21 | steps: 22 | - uses: actions/checkout@v4 23 | - uses: actions/setup-node@v4 24 | with: 25 | node-version: "20" 26 | - run: npm install -g yarn 27 | - run: yarn install 28 | - run: yarn run build 29 | 30 | - name: Test PR Commenter 31 | uses: ./ 32 | with: 33 | json-file: | 34 | test-data/tf_test.json 35 | test-data/tf_test2.json 36 | test-data/tf_test3.json 37 | 38 | - name: Test PR comment hiding 39 | uses: ./ 40 | with: 41 | json-file: | 42 | test-data/tf_test.json 43 | test-data/tf_test2.json 44 | test-data/tf_test3.json 45 | hide-previous-comments: true 46 | comment-header: "Same as previous but previous comment should be hidden." 47 | 48 | - name: Test PR Comment Expand feature 49 | uses: ./ 50 | with: 51 | json-file: test-data/tf_test.json 52 | expand-comment: "true" 53 | include-plan-job-summary: "true" 54 | comment-header: "BIG HEADER" 55 | comment-footer: "BIG FOOTER" 56 | include-workflow-link: "true" 57 | quiet: "true" 58 | include-job-link: "true" 59 | 60 | - name: Test PR Commenter with no changes 61 | uses: ./ 62 | with: 63 | json-file: test-data/tf_nochanges.json 64 | 65 | - name: Test PR Commenter with no resources 66 | uses: ./ 67 | with: 68 | json-file: test-data/tf_noresources.json 69 | 70 | - name: Test PR Commenter with large plan 71 | uses: ./ 72 | with: 73 | json-file: test-data/tf_test_large.json 74 | comment-header: "Large Plan Test" 75 | # We expect the comment to be truncated, so we don't need to check the full content 76 | # Just ensure the action runs without error and the summary is present 77 | include-plan-job-summary: true 78 | 79 | - name: Test PR comment hiding with default header 80 | id: hide_default_header 81 | uses: ./ 82 | with: 83 | json-file: test-data/tf_test.json 84 | hide-previous-comments: true 85 | - name: Assert PR comment hiding with default header 86 | run: | 87 | node -e " 88 | const output = process.env.COMMENT_BODY; 89 | if (!output.includes('Terraform Plan Changes for `test-data/tf_test.json`')) { 90 | console.error('Assertion failed: Missing header for tf_test.json'); 91 | process.exit(1); 92 | } 93 | " 94 | env: 95 | COMMENT_BODY: ${{ steps.hide_default_header.outputs.comment-body }} 96 | 97 | - name: Test multiline json files with hide previous comments and default header 98 | id: multiline_hide_default 99 | uses: ./ 100 | with: 101 | json-file: | 102 | test-data/tf_test.json 103 | test-data/tf_test2.json 104 | hide-previous-comments: true 105 | - name: Assert multiline json files with hide previous comments and default header 106 | run: | 107 | node -e " 108 | const output = process.env.COMMENT_BODY; 109 | if (!output.includes('Terraform Plan Changes for `test-data/tf_test.json`')) { 110 | console.error('Assertion failed: Missing header for tf_test.json'); 111 | process.exit(1); 112 | } 113 | if (!output.includes('Terraform Plan Changes for `test-data/tf_test2.json`')) { 114 | console.error('Assertion failed: Missing header for tf_test2.json'); 115 | process.exit(1); 116 | } 117 | " 118 | env: 119 | COMMENT_BODY: ${{ steps.multiline_hide_default.outputs.comment-body }} 120 | 121 | 122 | 123 | - name: Test multiple json files 124 | id: multiple_files 125 | uses: ./ 126 | with: 127 | json-file: | 128 | test-data/tf_test.json 129 | test-data/tf_test2.json 130 | 131 | - name: Assert multiple json files output 132 | run: | 133 | node -e " 134 | const output = process.env.COMMENT_BODY; 135 | if (!output.includes('Terraform Plan Changes for `test-data/tf_test.json`')) { 136 | console.error('Assertion failed: Missing header for tf_test.json'); 137 | process.exit(1); 138 | } 139 | if (!output.includes('Terraform Plan Changes for `test-data/tf_test2.json`')) { 140 | console.error('Assertion failed: Missing header for tf_test2.json'); 141 | process.exit(1); 142 | } 143 | " 144 | env: 145 | COMMENT_BODY: ${{ steps.multiple_files.outputs.comment-body }} 146 | 147 | matrix-plan: 148 | runs-on: ubuntu-latest 149 | strategy: 150 | matrix: 151 | json: 152 | - tf_test4 153 | steps: 154 | - uses: actions/checkout@v4 155 | - uses: actions/setup-node@v4 156 | with: 157 | node-version: "20" 158 | - run: npm install -g yarn 159 | - run: yarn install 160 | - run: yarn run build 161 | 162 | - name: Test PR Commenter with matrix job 163 | uses: ./ 164 | with: 165 | json-file: test-data/${{ matrix.json }}.json 166 | comment-header: Plan Summary for ${{ github.job }} (${{ matrix.json }}) 167 | quiet: true 168 | expand-comment: true 169 | hide-previous-comments: true 170 | include-workflow-link: true 171 | include-job-link: true 172 | include-plan-job-summary: true 173 | include-tag-only-resources: true 174 | include-unchanged-resources: true 175 | 176 | # Additional tests for pull_request_target event 177 | plan-pr-target: 178 | if: github.event_name == 'pull_request_target' 179 | runs-on: ubuntu-latest 180 | steps: 181 | - uses: actions/checkout@v4 182 | - uses: actions/setup-node@v4 183 | with: 184 | node-version: "20" 185 | - run: npm install -g yarn 186 | - run: yarn install 187 | - run: yarn run build 188 | 189 | - name: Test PR Commenter (pull_request_target) 190 | uses: ./ 191 | with: 192 | json-file: test-data/tf_test.json 193 | hide-previous-comments: true 194 | comment-header: "PR Target Event Test" 195 | 196 | # Test workflow_call functionality by calling a reusable workflow 197 | test-reusable-workflow: 198 | if: github.event_name == 'pull_request' 199 | uses: ./.github/workflows/reusable-terraform-test.yml 200 | with: 201 | test-mode: 'workflow_call_test' 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Terraform Change Pull Request Commenter Action 2 | This GitHub Action reads changes from your Terraform plan JSON output, summarizes the changes, and posts them in a single GitHub Pull Request comment. 3 | 4 | We recommend using this in your Infrastructure as Code delivery workflow to make any change visible and acclerate the PR review process. 5 | 6 | ## Why is this GitHub Action different than the other Terraform Plan commenters? 7 | 8 | Implementing this Action is _super_ simple and the comments are consise and easy to read. Other implementations may be heavily opinionated or require adding multiple jobs to your workflow. 9 | 10 | ## Features 11 | 12 | - Display changes in a Terraform plan without posting larger sections of the plan change log. This approach will, in most cases, avoid the situation where plan contents are too large for a single PR comment. 13 | - Collapsed as a summary by default, when expanded, the comment is broken up into sections for deletion, creation, and resource changes. The changes are also color-coded to help draw attention to each proposed modification. 14 | - This JavaScript GitHub Action runs directly on a host runner and executes faster than a Docker container Action. 15 | - Works with both direct pull request workflows (supports `pull_request` and `pull_request_target` events) and reusable workflows (`workflow_call` events). 16 | - Possibility to add the output to your workflow summary. 17 | - Possibility to hide previous comments generated by this action. 18 | - Possibility to not create any comments in case there are no infrastructure changes. 19 | - Customize the header and the footer of the generated output. 20 | 21 | ### Example Comment 22 | ![terraform-changes](./assets/terraform-changes.png) 23 | 24 | ## Inputs 25 | 26 | ### `json-file` 27 | 28 | **Optional** Defaults to `tfplan.json` 29 | 30 | - The location of the JSON file created by running `terraform show -no-color -json tfplan.plan > tfplan.json` (Or whatever you choose to name your plan or json outputs) 31 | 32 | - Multiple files can be provided using a text block. 33 | 34 | ### `github-token` 35 | 36 | **Optional** Boolean defaults to `${{github.token}}` 37 | 38 | - Used to authenticate with the GitHub API. 39 | 40 | ### `expand-comment` 41 | 42 | **Optional** Boolean defaults to `false` 43 | 44 | - Will expand the changes in comments by default rather than having them collapsed beneath the summary 45 | 46 | ### `include-plan-job-summary` 47 | 48 | **Optional** Defaults to `false` 49 | 50 | - Will write the plan output to the workflow summary. 51 | 52 | - The workflow summary will still be set when running this action outside of a PR context. 53 | 54 | ### `comment-header` 55 | 56 | **Optional** Defaults to `Terraform Plan Changes` 57 | 58 | - Will set the header of the PR comment and/or workflow summary. The filename will always be appended to this header. 59 | 60 | ### `comment-footer` 61 | 62 | **Optional** Defaults to `""` 63 | 64 | - Will set a footer of the PR comment and/or workflow summary. 65 | 66 | ### `include-workflow-link` 67 | 68 | **Optional** Defaults to `false` 69 | 70 | - Will include a link back to the workflow in the PR comment and/or workflow summary. 71 | 72 | ### `quiet` 73 | 74 | **Optional** Defaults to `false` 75 | 76 | - Will not create a PR comment when there are no infrastructure changes. 77 | 78 | ### `hide-previous-comments` 79 | 80 | **Optional** Defaults to `false` 81 | 82 | - Will hide/minimize all previous comments generated by this action. 83 | - When using this feature within a matrix, ensure you set `comment-header` to a unique value per matrix job (e.g., `comment-header: Plan Summary for ${{ matrix.module }}`). This ensures the action can properly identify and manage comments from each matrix job independently. 84 | 85 | ### `log-changed-resources` 86 | 87 | **Optional** Defaults to `true` 88 | 89 | - Logs all the changed resources found in the plan to the action output. 90 | 91 | ## Example usage 92 | 93 | > ‼️ Do not forget to add pull-requests write permission to your github action definition. [More info](https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#defining-access-for-the-github_token-scopes) 94 | 95 | ```yaml 96 | permissions: 97 | pull-requests: write 98 | ``` 99 | Single plan file: 100 | ```yaml 101 | uses: liatrio/terraform-change-pr-commenter@v1.10.0 102 | with: 103 | json-file: my-tfplan.json 104 | expand-comment: 'true' 105 | ``` 106 | Multiple plan files: 107 | ```yaml 108 | uses: liatrio/terraform-change-pr-commenter@v1.10.0 109 | with: 110 | json-file: | 111 | core-infra-tfplan.json 112 | shared-infra-tfplan.json 113 | ``` 114 | Include plan output to the Actions workflow job summary: 115 | ```yaml 116 | uses: liatrio/terraform-change-pr-commenter@v1.10.0 117 | with: 118 | json-file: my-tfplan.json 119 | expand-comment: 'true' 120 | include-plan-job-summary: 'true' 121 | ``` 122 | **Note:** 123 | - When `include-plan-job-summary = true`, if the action is executed in non-Pull Request workflows, the plan output will also be posted to the job summary of that run. If you do not wish to have this behavior, apply conditional logic to your workflow file. 124 | 125 | ### Usage with Reusable Workflows 126 | 127 | This action works seamlessly with reusable workflows. When called through a `workflow_call` event, it will still properly comment on the originating pull request. 128 | 129 | **Important:** For `pull_request_target` and `workflow_call` events, the action requires that the originating event was triggered by a pull request so that the necessary PR context is available. If a reusable workflow is called from a non-PR event (like `push`, `schedule`, or `workflow_dispatch`), the action will skip comment creation and only generate workflow summaries if enabled. 130 | 131 | **reusable-terraform.yml:** 132 | ```yaml 133 | name: Reusable Terraform Workflow 134 | 135 | on: 136 | workflow_call: 137 | inputs: 138 | environment: 139 | required: true 140 | type: string 141 | 142 | jobs: 143 | terraform: 144 | runs-on: ubuntu-latest 145 | steps: 146 | - uses: actions/checkout@v4 147 | - uses: hashicorp/setup-terraform@v2 148 | with: 149 | terraform_wrapper: false 150 | 151 | - name: Terraform Plan 152 | run: | 153 | terraform init 154 | terraform plan -out=tfplan 155 | terraform show -json tfplan > tfplan.json 156 | 157 | - name: Comment Plan Changes 158 | uses: liatrio/terraform-change-pr-commenter@v1.10.0 159 | with: 160 | json-file: tfplan.json 161 | comment-header: "Terraform Plan for ${{ inputs.environment }}" 162 | expand-comment: 'true' 163 | ``` 164 | 165 | **main-workflow.yml:** 166 | ```yaml 167 | name: Infrastructure Deployment 168 | 169 | on: 170 | pull_request: 171 | 172 | permissions: 173 | pull-requests: write 174 | 175 | jobs: 176 | terraform-dev: 177 | uses: ./.github/workflows/reusable-terraform.yml 178 | with: 179 | environment: "development" 180 | 181 | terraform-prod: 182 | uses: ./.github/workflows/reusable-terraform.yml 183 | with: 184 | environment: "production" 185 | ``` 186 | 187 | #### Example Job Summary Output 188 | ![Plan output job summary](assets/plan-output-job-summary.png) 189 | 190 | ## Example usage with OpenTofu 191 | 192 | To use this action with OpenTofu you need to initialize OpenTofu without the wrapper, like discussed in the `known issues` below. 193 | 194 | **You also need to convert the planfile to a JSON planfile using the `tofu show -json` command.** 195 | 196 | ```yaml 197 | - uses: opentofu/setup-opentofu@v1 198 | with: 199 | tofu_wrapper: false 200 | 201 | - name: Create planfile 202 | run: tofu plan -no-color -out=./.planfile 203 | 204 | - name: Convert planfile to JSON planfile 205 | run: tofu show -json ./.planfile >> ./my-planfile.json 206 | 207 | - name: Create PR comment 208 | uses: liatrio/terraform-change-pr-commenter@v1.10.0 209 | with: 210 | json-file: my-planfile.json 211 | ``` 212 | 213 | ## Terraform Configuration / Known Issues 214 | #### Known issue when including the [Terraform Wrapper script](https://github.com/hashicorp/setup-terraform#inputs) 215 | - Execution may error with `Error: Unexpected token c in JSON at position 1` 216 | - **Cause**: Terraform wrapper enabled (default behavior) causes invalid JSON in Terraform output. 217 | - **Fix**: Exclude the Terraform Wrapper when setting up Terraform (*GitHub Actions example*) 218 | ```yaml 219 | - name: Setup Terraform 220 | uses: hashicorp/setup-terraform@v2 221 | with: 222 | terraform_wrapper: false 223 | ``` 224 | 225 | ## Contributing or Submitting Issues 226 | 227 | ### Contributions are welcome! 228 | If you'd like to suggest changes, feel free to submit a Pull Request or [open an issue](https://github.com/liatrio/terraform-change-pr-commenter/issues/new). 229 | 230 | Otherwise if things aren't working as expected, please [open a new issue](https://github.com/liatrio/terraform-change-pr-commenter/issues/new). Please include code references, a description of the issue, and expected behavior. 231 | 232 | --- 233 | ![CodeQL Security Scan](https://github.com/liatrio/terraform-change-pr-commenter/actions/workflows/codeql-analysis.yml/badge.svg?branch=main) 234 | ![Release](https://github.com/liatrio/terraform-change-pr-commenter/actions/workflows/release.yml/badge.svg?branch=main) 235 | [![semantic-release: angular](https://img.shields.io/badge/semantic--release-angular-e10079?logo=semantic-release)](https://github.com/semantic-release/semantic-release) 236 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # [1.14.0](https://github.com/liatrio/terraform-change-pr-commenter/compare/v1.13.0...v1.14.0) (2025-07-01) 2 | 3 | 4 | ### Features 5 | 6 | * **action:** add support for `pull_request_target` event ([#95](https://github.com/liatrio/terraform-change-pr-commenter/issues/95)) ([fdfdbae](https://github.com/liatrio/terraform-change-pr-commenter/commit/fdfdbae2c1dbf02ed6a6334a334b99d2ed28f531)), closes [#94](https://github.com/liatrio/terraform-change-pr-commenter/issues/94) 7 | 8 | # [1.13.0](https://github.com/liatrio/terraform-change-pr-commenter/compare/v1.12.0...v1.13.0) (2025-06-27) 9 | 10 | 11 | ### Features 12 | 13 | * Truncate PR comments if too long ([#93](https://github.com/liatrio/terraform-change-pr-commenter/issues/93)) ([5587334](https://github.com/liatrio/terraform-change-pr-commenter/commit/55873345015c06f59316309a71ea9433104ed5f9)), closes [#91](https://github.com/liatrio/terraform-change-pr-commenter/issues/91) 14 | 15 | # [1.12.0](https://github.com/liatrio/terraform-change-pr-commenter/compare/v1.11.0...v1.12.0) (2025-06-27) 16 | 17 | 18 | ### Features 19 | 20 | * Simplify comment-header logic and improve multi-file support ([#92](https://github.com/liatrio/terraform-change-pr-commenter/issues/92)) ([de714c9](https://github.com/liatrio/terraform-change-pr-commenter/commit/de714c9edf0859d9851946cd93864c3b789e626a)) 21 | 22 | # [1.11.0](https://github.com/liatrio/terraform-change-pr-commenter/compare/v1.10.1...v1.11.0) (2025-06-16) 23 | 24 | 25 | ### Features 26 | 27 | * allow workflow calls as triggers ([#89](https://github.com/liatrio/terraform-change-pr-commenter/issues/89)) ([bd5d6aa](https://github.com/liatrio/terraform-change-pr-commenter/commit/bd5d6aafb8c90a8cc0e3d78c32a0f33fcffa27de)) 28 | 29 | ## [1.10.1](https://github.com/liatrio/terraform-change-pr-commenter/compare/v1.10.0...v1.10.1) (2025-05-30) 30 | 31 | 32 | ### Bug Fixes 33 | 34 | * handle comment if no resources ([#88](https://github.com/liatrio/terraform-change-pr-commenter/issues/88)) ([4666dab](https://github.com/liatrio/terraform-change-pr-commenter/commit/4666dabe39891932028ca1b53a2172590009bad5)) 35 | 36 | # [1.10.0](https://github.com/liatrio/terraform-change-pr-commenter/compare/v1.9.0...v1.10.0) (2025-04-29) 37 | 38 | 39 | ### Features 40 | 41 | * Add tags tracking, unchanged resources, and matrix support for jobs ([#87](https://github.com/liatrio/terraform-change-pr-commenter/issues/87)) ([b2f5356](https://github.com/liatrio/terraform-change-pr-commenter/commit/b2f535616c169467e523e6ff35ba684606ee2521)) 42 | 43 | # [1.9.0](https://github.com/liatrio/terraform-change-pr-commenter/compare/v1.8.0...v1.9.0) (2025-04-24) 44 | 45 | 46 | ### Features 47 | 48 | * Add GitHub Actions to CodeQL analysis matrix ([#86](https://github.com/liatrio/terraform-change-pr-commenter/issues/86)) ([d410b01](https://github.com/liatrio/terraform-change-pr-commenter/commit/d410b015e84293a722b73dd529393aeaf2b2cacf)) 49 | 50 | # [1.8.0](https://github.com/liatrio/terraform-change-pr-commenter/compare/v1.7.1...v1.8.0) (2025-04-24) 51 | 52 | 53 | ### Features 54 | 55 | * Add job link option, resolves [#84](https://github.com/liatrio/terraform-change-pr-commenter/issues/84) ([#85](https://github.com/liatrio/terraform-change-pr-commenter/issues/85)) ([0b450ba](https://github.com/liatrio/terraform-change-pr-commenter/commit/0b450ba53b357f81b54bf117c9dab15e2fd6cda8)) 56 | 57 | ## [1.7.1](https://github.com/liatrio/terraform-change-pr-commenter/compare/v1.7.0...v1.7.1) (2024-12-12) 58 | 59 | 60 | ### Bug Fixes 61 | 62 | * `hide-previous-comment` now can handel matrix strategy runs when given a unique `comment-header` ([#78](https://github.com/liatrio/terraform-change-pr-commenter/issues/78)) ([95ca081](https://github.com/liatrio/terraform-change-pr-commenter/commit/95ca081372ca566e0c8577d24353842679b527ee)) 63 | 64 | # [1.7.0](https://github.com/liatrio/terraform-change-pr-commenter/compare/v1.6.0...v1.7.0) (2024-09-03) 65 | 66 | 67 | ### Features 68 | 69 | * adds an input for showing the full list of changed resources in the action output ([#68](https://github.com/liatrio/terraform-change-pr-commenter/issues/68)) ([815d669](https://github.com/liatrio/terraform-change-pr-commenter/commit/815d669c00d3bcb18303a846c49ef49cd2ab19db)) 70 | 71 | # [1.6.0](https://github.com/liatrio/terraform-change-pr-commenter/compare/v1.5.0...v1.6.0) (2024-09-03) 72 | 73 | 74 | ### Features 75 | 76 | * ability to hide previous comments & fix for summary issue ([#65](https://github.com/liatrio/terraform-change-pr-commenter/issues/65)) ([08ba12c](https://github.com/liatrio/terraform-change-pr-commenter/commit/08ba12cd559192754993f85f0e45de37f095e248)) 77 | 78 | # [1.5.0](https://github.com/liatrio/terraform-change-pr-commenter/compare/v1.4.5...v1.5.0) (2024-05-08) 79 | 80 | 81 | ### Features 82 | 83 | * additional feature additions ([#62](https://github.com/liatrio/terraform-change-pr-commenter/issues/62)) ([1465fa2](https://github.com/liatrio/terraform-change-pr-commenter/commit/1465fa28232ee9e3b51c5db1fa43f2c2f4b971e4)) 84 | * multiple feature addition [#58](https://github.com/liatrio/terraform-change-pr-commenter/issues/58) ([#60](https://github.com/liatrio/terraform-change-pr-commenter/issues/60)) ([01f0321](https://github.com/liatrio/terraform-change-pr-commenter/commit/01f0321246312425041b0ee8eaa5ba9404f6f1ae)) 85 | 86 | 87 | ### Reverts 88 | 89 | * Revert " feat: multiple feature addition #58 (#60)" (#63) ([ab68bb6](https://github.com/liatrio/terraform-change-pr-commenter/commit/ab68bb614b5eb42957331703bf7afa80e1188186)), closes [#58](https://github.com/liatrio/terraform-change-pr-commenter/issues/58) [#60](https://github.com/liatrio/terraform-change-pr-commenter/issues/60) [#63](https://github.com/liatrio/terraform-change-pr-commenter/issues/63) 90 | 91 | ## [1.4.5](https://github.com/liatrio/terraform-change-pr-commenter/compare/v1.4.4...v1.4.5) (2024-02-02) 92 | 93 | 94 | ### Bug Fixes 95 | 96 | * Update actions to use actions with versions with node20 ([#56](https://github.com/liatrio/terraform-change-pr-commenter/issues/56)) ([2365114](https://github.com/liatrio/terraform-change-pr-commenter/commit/236511422a9364c7adb215a172eec7173ce18374)) 97 | * Update release.yml ([#55](https://github.com/liatrio/terraform-change-pr-commenter/issues/55)) ([d527888](https://github.com/liatrio/terraform-change-pr-commenter/commit/d5278883cce02e2713a70a70b80adbf7390a7476)) 98 | 99 | ## [1.4.5](https://github.com/liatrio/terraform-change-pr-commenter/compare/v1.4.4...v1.4.5) (2024-02-02) 100 | 101 | 102 | ### Bug Fixes 103 | 104 | * Update release.yml ([#55](https://github.com/liatrio/terraform-change-pr-commenter/issues/55)) ([d527888](https://github.com/liatrio/terraform-change-pr-commenter/commit/d5278883cce02e2713a70a70b80adbf7390a7476)) 105 | 106 | ## [1.4.4](https://github.com/liatrio/terraform-change-pr-commenter/compare/v1.4.3...v1.4.4) (2024-02-02) 107 | 108 | 109 | ### Bug Fixes 110 | 111 | * update line 24 to node20 ([#53](https://github.com/liatrio/terraform-change-pr-commenter/issues/53)) ([d84a976](https://github.com/liatrio/terraform-change-pr-commenter/commit/d84a976ce8bee75080d34f46b39d1c28f2cfec3a)) 112 | 113 | ## [1.4.2](https://github.com/liatrio/terraform-change-pr-commenter/compare/v1.4.1...v1.4.2) (2024-02-01) 114 | 115 | 116 | ### Bug Fixes 117 | 118 | * Node bump to 20 from 16 ([#51](https://github.com/liatrio/terraform-change-pr-commenter/issues/51)) ([2da4521](https://github.com/liatrio/terraform-change-pr-commenter/commit/2da45213eef1edc22a05b22bb198b0d94e0cf2a0)) 119 | 120 | # [1.4.0](https://github.com/liatrio/terraform-change-pr-commenter/compare/v1.3.3...v1.4.0) (2023-01-09) 121 | 122 | 123 | ### Features 124 | 125 | * add job summary ([#36](https://github.com/liatrio/terraform-change-pr-commenter/issues/36)) ([01d3b49](https://github.com/liatrio/terraform-change-pr-commenter/commit/01d3b49e93cf0319d28dee2b3fbab268b6566df9)) 126 | 127 | ## [1.3.2](https://github.com/liatrio/terraform-change-pr-commenter/compare/v1.3.1...v1.3.2) (2022-06-09) 128 | 129 | 130 | ### Bug Fixes 131 | 132 | * [#30](https://github.com/liatrio/terraform-change-pr-commenter/issues/30) empty plan would failed the action ([#31](https://github.com/liatrio/terraform-change-pr-commenter/issues/31)) ([c4ea052](https://github.com/liatrio/terraform-change-pr-commenter/commit/c4ea0520ce5c086465dda4da3f75fca6527a60e0)) 133 | 134 | ## [1.3.1](https://github.com/liatrio/terraform-change-pr-commenter/compare/v1.3.0...v1.3.1) (2022-04-29) 135 | 136 | 137 | ### Bug Fixes 138 | 139 | * operator for replace was broken in last fixes ([#25](https://github.com/liatrio/terraform-change-pr-commenter/issues/25)) ([e82bf94](https://github.com/liatrio/terraform-change-pr-commenter/commit/e82bf94e915ad440bd0c08e69dcd9ef748a74ed2)) 140 | 141 | # [1.3.0](https://github.com/liatrio/terraform-change-pr-commenter/compare/v1.2.0...v1.3.0) (2022-04-29) 142 | 143 | 144 | ### Features 145 | 146 | * added support for 'replace', and 'unchanged' ([#24](https://github.com/liatrio/terraform-change-pr-commenter/issues/24)) ([a3c45b0](https://github.com/liatrio/terraform-change-pr-commenter/commit/a3c45b0c735a3c4467729d0f94730c2af583a5e2)) 147 | 148 | # [1.2.0](https://github.com/liatrio/terraform-change-pr-commenter/compare/v1.1.0...v1.2.0) (2022-04-01) 149 | 150 | 151 | ### Features 152 | 153 | * adding comment block expand flag ([55d2573](https://github.com/liatrio/terraform-change-pr-commenter/commit/55d25736974196a554e7ed4d864224b54af0123d)) 154 | 155 | # [1.1.0](https://github.com/liatrio/terraform-change-pr-commenter/compare/v1.0.2...v1.1.0) (2022-02-23) 156 | 157 | 158 | ### Features 159 | 160 | * Support for multiple plans ([#13](https://github.com/liatrio/terraform-change-pr-commenter/issues/13)) ([9dc08b0](https://github.com/liatrio/terraform-change-pr-commenter/commit/9dc08b01a7f2000f9a8721c4be3479079642580e)) 161 | 162 | ## [1.0.2](https://github.com/liatrio/terraform-change-pr-commenter/compare/v1.0.1...v1.0.2) (2022-02-13) 163 | 164 | 165 | ### Bug Fixes 166 | 167 | * using yarn build to remove npm dependency vulnerabilities ([3777d7b](https://github.com/liatrio/terraform-change-pr-commenter/commit/3777d7bb2204009d82f659632a95372e71c08dfc)) 168 | 169 | ## [1.0.1](https://github.com/liatrio/terraform-change-pr-commenter/compare/v1.0.0...v1.0.1) (2022-02-05) 170 | 171 | 172 | ### Bug Fixes 173 | 174 | * adding branding to the action ([e40fd0c](https://github.com/liatrio/terraform-change-pr-commenter/commit/e40fd0c772ab36937de7e86ae71e3e6f013b5a70)) 175 | 176 | # 1.0.0 (2022-01-29) 177 | 178 | 179 | ### Features 180 | 181 | * initial release v1.0.0 ([90eaf6e](https://github.com/liatrio/terraform-change-pr-commenter/commit/90eaf6ef9875330479e2368eaf669099c740b006)) 182 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const core = require("@actions/core"); 2 | const github = require("@actions/github"); 3 | const fs = require("fs"); 4 | 5 | const expandDetailsComment = core.getBooleanInput("expand-comment"); 6 | const includePlanSummary = core.getBooleanInput("include-plan-job-summary"); 7 | const myToken = core.getInput("github-token"); 8 | const octokit = github.getOctokit(myToken); 9 | const context = github.context; 10 | const inputFilenames = core.getMultilineInput("json-file"); 11 | const commentHeader = core.getMultilineInput("comment-header"); 12 | const commentFooter = core.getMultilineInput("comment-footer"); 13 | const quietMode = core.getBooleanInput("quiet"); 14 | const includeLinkToWorkflow = core.getBooleanInput("include-workflow-link"); 15 | const includeLinkToJob = core.getBooleanInput("include-job-link"); 16 | const hidePreviousComments = core.getBooleanInput("hide-previous-comments"); 17 | const logChangedResources = core.getBooleanInput("log-changed-resources"); 18 | const includeTagOnlyResources = core.getBooleanInput( 19 | "include-tag-only-resources", 20 | ); 21 | const includeUnchangedResources = core.getBooleanInput( 22 | "include-unchanged-resources", 23 | ); 24 | 25 | const MAX_COMMENT_LENGTH = 65536; 26 | 27 | // Get current job name from GitHub environment variable 28 | const currentJobName = process.env.GITHUB_JOB || ""; 29 | const currentRunnerName = process.env.RUNNER_NAME || ""; 30 | 31 | // Log the job name for debugging 32 | console.log("Current job name:", currentJobName); 33 | 34 | const workflowLink = includeLinkToWorkflow 35 | ? ` 36 | [Workflow: ${context.workflow}](${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}) 37 | ` 38 | : ""; 39 | 40 | // Initialize job link as empty string 41 | let jobLink = ""; 42 | 43 | // Function to get job ID from GitHub API 44 | async function getJobId() { 45 | if (includeLinkToJob) { 46 | try { 47 | // Get all jobs for the current workflow run 48 | const response = await octokit.rest.actions.listJobsForWorkflowRun({ 49 | owner: context.repo.owner, 50 | repo: context.repo.repo, 51 | run_id: context.runId, 52 | }); 53 | 54 | // Find the current job by name 55 | const job = response.data.jobs.find( 56 | (job) => 57 | job.runner_name === currentRunnerName && 58 | (job.name.endsWith(currentJobName) || 59 | job.name.startsWith(currentJobName)), 60 | ); 61 | 62 | if (job) { 63 | console.log(`Found job ID: ${job.id} for job name: ${job.name}`); 64 | // Create job link with the numeric job ID 65 | return ` 66 | [Job: ${job.name}](${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}/job/${job.id}) 67 | `; 68 | } else { 69 | console.log(`Could not find job with name: ${currentJobName}`); 70 | console.log(`Jobs: \n${JSON.stringify(response.data.jobs, null, 2)}`); 71 | return ""; 72 | } 73 | } catch (error) { 74 | console.error(`Error fetching job ID: ${error.message}`); 75 | return ""; 76 | } 77 | } 78 | return ""; 79 | } 80 | 81 | var hasNoChanges = false; 82 | 83 | // GraphQL queries and mutations used for hiding previous comments 84 | const minimizeCommentQuery = /* GraphQL */ ` 85 | mutation minimizeComment($id: ID!) { 86 | minimizeComment(input: { classifier: OUTDATED, subjectId: $id }) { 87 | clientMutationId 88 | } 89 | } 90 | `; 91 | 92 | const commentsQuery = /* GraphQL */ ` 93 | query comments($owner: String!, $name: String!, $number: Int!) { 94 | repository(owner: $owner, name: $name) { 95 | pullRequest(number: $number) { 96 | comments(last: 100, orderBy: { field: UPDATED_AT, direction: DESC }) { 97 | nodes { 98 | id 99 | body 100 | isMinimized 101 | } 102 | } 103 | } 104 | } 105 | } 106 | `; 107 | 108 | const output = () => { 109 | let body = ""; 110 | // for each file 111 | for (const file of inputFilenames) { 112 | const resource_changes = 113 | JSON.parse(fs.readFileSync(file)).resource_changes || []; 114 | try { 115 | let changed_resources = resource_changes.filter((resource) => { 116 | return resource.change.actions != ["no-op"]; 117 | }); 118 | 119 | if (logChangedResources) { 120 | console.log("changed_resources", changed_resources); 121 | } 122 | if (Array.isArray(resource_changes) && resource_changes.length > 0) { 123 | const resources_to_create = [], 124 | resources_to_update = [], 125 | resources_to_delete = [], 126 | resources_to_replace = [], 127 | resources_to_tag = [], 128 | resources_unchanged = []; 129 | 130 | // Deep comparison function to check if objects are identical after removing tags 131 | const isTagOnlyChange = (before, after) => { 132 | if (includeTagOnlyResources == false) { 133 | return false; 134 | } 135 | const beforeCopy = JSON.parse(JSON.stringify(before || {})); 136 | const afterCopy = JSON.parse(JSON.stringify(after || {})); 137 | 138 | delete beforeCopy.tags; 139 | delete beforeCopy.tags_all; 140 | delete afterCopy.tags; 141 | delete afterCopy.tags_all; 142 | 143 | return JSON.stringify(beforeCopy) === JSON.stringify(afterCopy); 144 | }; 145 | 146 | // for each resource changes 147 | for (const resource of resource_changes) { 148 | const change = resource.change; 149 | const address = resource.address; 150 | 151 | switch (change.actions[0]) { 152 | default: 153 | break; 154 | case "no-op": 155 | resources_unchanged.push(address); 156 | break; 157 | case "create": 158 | resources_to_create.push(address); 159 | break; 160 | case "delete": 161 | if (change.actions.length > 1) { 162 | resources_to_replace.push(address); 163 | } else { 164 | resources_to_delete.push(address); 165 | } 166 | break; 167 | case "update": 168 | if (isTagOnlyChange(change.before, change.after)) { 169 | resources_to_tag.push(address); 170 | } else { 171 | resources_to_update.push(address); 172 | } 173 | break; 174 | } 175 | } 176 | // the body must be indented at the start otherwise 177 | // there will be formatting error when comment is 178 | // showed on GitHub 179 | let planSummary = `Terraform Plan: ${resources_to_create.length} to be created, ${resources_to_delete.length} to be deleted, ${resources_to_update.length} to be updated${includeTagOnlyResources ? `, ${resources_to_tag.length} to be tagged` : ""}, ${resources_to_replace.length} to be replaced, ${resources_unchanged.length} unchanged.`; 180 | 181 | let fullBody = ` 182 | ${commentHeader} for \`${file}\` 183 |
184 | 185 | ${planSummary} 186 | 187 | ${includeUnchangedResources ? details("unchanged", resources_unchanged, "•") : ""} 188 | ${details("create", resources_to_create, "+")} 189 | ${details("delete", resources_to_delete, "-")} 190 | ${details("update", resources_to_update, "!")} 191 | ${includeTagOnlyResources ? details("tag", resources_to_tag, "!") : ""} 192 | ${details("replace", resources_to_replace, "+")} 193 |
194 | ${commentFooter.map((a) => (a == "" ? "\n" : a)).join("\n")} 195 | ${workflowLink} 196 | ${jobLink} 197 | `; 198 | 199 | if (fullBody.length > MAX_COMMENT_LENGTH) { 200 | body += ` 201 | ${commentHeader} for \`${file}\` 202 | ${planSummary} 203 |

Sorry, the detailed plan exceeded GitHub's comment size limit (${MAX_COMMENT_LENGTH} characters) and has been truncated. Please see the workflow run for the full plan output.

204 | ${commentFooter.map((a) => (a == "" ? "\n" : a)).join("\n")} 205 | ${workflowLink} 206 | ${jobLink} 207 | `; 208 | } else { 209 | body += fullBody; 210 | } 211 | if ( 212 | resources_to_create + 213 | resources_to_delete + 214 | resources_to_update + 215 | resources_to_tag + 216 | resources_to_replace == 217 | [] 218 | ) { 219 | hasNoChanges = true; 220 | } 221 | } else { 222 | hasNoChanges = true; 223 | console.log( 224 | "No changes found in the plan. setting hasNoChanges to true.", 225 | ); 226 | body += ` 227 |

There were no changes done to the infrastructure.

228 | `; 229 | core.info( 230 | `"The content of ${file} did not result in a valid array or the array is empty... Skipping."`, 231 | ); 232 | } 233 | } catch (error) { 234 | core.error(`${file} is not a valid JSON file. error: ${error}`); 235 | } 236 | } 237 | return body; 238 | }; 239 | 240 | const details = (action, resources, operator) => { 241 | let str_title = ""; 242 | let str = ""; 243 | 244 | if (resources.length !== 0) { 245 | if (action === "unchanged") { 246 | str_title = "Unchanged resources"; 247 | } else { 248 | str_title = `Resources to ${action}`; 249 | } 250 | str = ` 251 | #### ${str_title}\n 252 | \`\`\`diff\n 253 | `; 254 | for (const el of resources) { 255 | // In the replace block, we show delete (-) and then create (+) 256 | if (action === "replace") { 257 | str += `- ${el}\n`; 258 | } 259 | str += `${operator} ${el}\n`; 260 | } 261 | 262 | str += "```\n"; 263 | } 264 | 265 | return str; 266 | }; 267 | 268 | const queryComments = (variables) => { 269 | return octokit.graphql(commentsQuery, variables); 270 | }; 271 | 272 | const minimizeComment = (variables) => { 273 | return octokit.graphql(minimizeCommentQuery, variables); 274 | }; 275 | 276 | const hideComments = () => { 277 | core.info(`Hiding previous comments.`); 278 | 279 | queryComments({ 280 | owner: context.repo.owner, 281 | name: context.repo.repo, 282 | number: context.issue.number, 283 | }) 284 | .then((response) => { 285 | core.info( 286 | `Successfully retrieved comments for PR #${context.issue.number}.`, 287 | ); 288 | const comments = response.repository.pullRequest.comments.nodes; 289 | 290 | core.info(`Found ${comments.length} comments in the PR.`); 291 | 292 | core.info(`Comment header used for matching is: ${commentHeader}`); 293 | 294 | filteredComments = comments.filter( 295 | (comment) => 296 | comment.body.includes("Terraform Plan:") || 297 | comment.body.includes( 298 | "There were no changes done to the infrastructure.", 299 | ), 300 | ); 301 | 302 | core.info( 303 | `Filtered down to ${filteredComments.length} comments created by this action.`, 304 | ); 305 | 306 | filteredComments = filteredComments.filter((comment) => 307 | comment.body.includes(commentHeader), 308 | ); 309 | 310 | core.info( 311 | `Filtered down to ${filteredComments.length} comments created by this action.`, 312 | ); 313 | 314 | filteredComments = filteredComments.filter((comment) => 315 | comment.body.includes(commentHeader), 316 | ); 317 | 318 | core.info( 319 | `Filtered down to ${filteredComments.length} comments that need to be minimized.`, 320 | ); 321 | 322 | const minimizePromises = filteredComments 323 | .filter((comment) => !comment.isMinimized) 324 | .map((comment) => { 325 | return minimizeComment({ id: comment.id }).catch((error) => 326 | core.error( 327 | `Failed to minimize comment ${comment.id}: ${error.message}`, 328 | ), 329 | ); 330 | }); 331 | 332 | return Promise.all(minimizePromises) 333 | .then(() => core.info("All minimize operations completed.")) 334 | .catch((error) => 335 | core.error(`Error during minimize operations: ${error.message}`), 336 | ); 337 | }) 338 | .catch((error) => 339 | core.error(`Failed to retrieve comments: ${error.message}`), 340 | ); 341 | }; 342 | 343 | // Main execution wrapped in an async function to allow for await 344 | async function run() { 345 | try { 346 | // Get job link if needed 347 | if (includeLinkToJob) { 348 | jobLink = await getJobId(); 349 | console.log("Job link generated:", jobLink); 350 | } 351 | 352 | let rawOutput = output(); 353 | let createComment = true; 354 | 355 | console.log("hidePreviousComments", hidePreviousComments); 356 | console.log( 357 | "hidePreviousComments && context.eventName === pull_request", 358 | hidePreviousComments && (context.eventName === "pull_request" || context.eventName === "pull_request_target"), 359 | ); 360 | if (hidePreviousComments && (context.eventName === "pull_request" || context.eventName === "pull_request_target")) { 361 | hideComments(); 362 | } 363 | 364 | console.log("includePlanSummary", includePlanSummary); 365 | if (includePlanSummary) { 366 | core.info("Adding plan output to job summary"); 367 | core.summary 368 | .addHeading("Terraform Plan Results") 369 | .addRaw(rawOutput) 370 | .write(); 371 | } 372 | 373 | console.log("quietMode", quietMode); 374 | console.log("hasNoChanges", hasNoChanges); 375 | console.log("quietMode && hasNoChanges", quietMode && hasNoChanges); 376 | if (quietMode && hasNoChanges) { 377 | core.info( 378 | "quiet mode is enabled and there are no changes to the infrastructure.", 379 | ); 380 | core.info("Skipping comment creation."); 381 | createComment = false; 382 | } 383 | 384 | if ( 385 | context.eventName === "pull_request" || 386 | context.eventName === "pull_request_target" || 387 | context.eventName === "workflow_call" 388 | ) { 389 | // Verify we have PR context available in the case that it's a workflow_call event- should always pass for pull_request 390 | if (context.issue && context.issue.number) { 391 | core.info( 392 | `Found PR # ${context.issue.number} from ${context.eventName} event - proceeding to comment.`, 393 | ); 394 | } else { 395 | core.info( 396 | `${context.eventName} event detected but no PR context available.`, 397 | ); 398 | core.info("Skipping comment creation."); 399 | createComment = false; 400 | } 401 | } else { 402 | core.info("Action doesn't seem to be running in a PR workflow context."); 403 | core.info("Skipping comment creation."); 404 | createComment = false; 405 | } 406 | 407 | if (createComment) { 408 | core.info("Adding comment to PR"); 409 | core.info(`Comment: ${rawOutput}`); 410 | octokit.rest.issues.createComment({ 411 | issue_number: context.issue.number, 412 | owner: context.repo.owner, 413 | repo: context.repo.repo, 414 | body: rawOutput, 415 | }); 416 | core.info("Comment added successfully."); 417 | } 418 | core.setOutput("comment-body", rawOutput); 419 | } catch (error) { 420 | core.setFailed(error.message); 421 | } 422 | } 423 | 424 | // Execute the main function 425 | run(); 426 | -------------------------------------------------------------------------------- /dist/licenses.txt: -------------------------------------------------------------------------------- 1 | @actions/core 2 | MIT 3 | The MIT License (MIT) 4 | 5 | Copyright 2019 GitHub 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 10 | 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 12 | 13 | @actions/github 14 | MIT 15 | The MIT License (MIT) 16 | 17 | Copyright 2019 GitHub 18 | 19 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 20 | 21 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 22 | 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | @actions/http-client 26 | MIT 27 | Actions Http Client for Node.js 28 | 29 | Copyright (c) GitHub, Inc. 30 | 31 | All rights reserved. 32 | 33 | MIT License 34 | 35 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 36 | associated documentation files (the "Software"), to deal in the Software without restriction, 37 | including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 38 | and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 39 | subject to the following conditions: 40 | 41 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 42 | 43 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 44 | LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 45 | NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 46 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 47 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 48 | 49 | 50 | @octokit/auth-token 51 | MIT 52 | The MIT License 53 | 54 | Copyright (c) 2019 Octokit contributors 55 | 56 | Permission is hereby granted, free of charge, to any person obtaining a copy 57 | of this software and associated documentation files (the "Software"), to deal 58 | in the Software without restriction, including without limitation the rights 59 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 60 | copies of the Software, and to permit persons to whom the Software is 61 | furnished to do so, subject to the following conditions: 62 | 63 | The above copyright notice and this permission notice shall be included in 64 | all copies or substantial portions of the Software. 65 | 66 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 67 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 68 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 69 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 70 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 71 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 72 | THE SOFTWARE. 73 | 74 | 75 | @octokit/core 76 | MIT 77 | The MIT License 78 | 79 | Copyright (c) 2019 Octokit contributors 80 | 81 | Permission is hereby granted, free of charge, to any person obtaining a copy 82 | of this software and associated documentation files (the "Software"), to deal 83 | in the Software without restriction, including without limitation the rights 84 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 85 | copies of the Software, and to permit persons to whom the Software is 86 | furnished to do so, subject to the following conditions: 87 | 88 | The above copyright notice and this permission notice shall be included in 89 | all copies or substantial portions of the Software. 90 | 91 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 92 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 93 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 94 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 95 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 96 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 97 | THE SOFTWARE. 98 | 99 | 100 | @octokit/endpoint 101 | MIT 102 | The MIT License 103 | 104 | Copyright (c) 2018 Octokit contributors 105 | 106 | Permission is hereby granted, free of charge, to any person obtaining a copy 107 | of this software and associated documentation files (the "Software"), to deal 108 | in the Software without restriction, including without limitation the rights 109 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 110 | copies of the Software, and to permit persons to whom the Software is 111 | furnished to do so, subject to the following conditions: 112 | 113 | The above copyright notice and this permission notice shall be included in 114 | all copies or substantial portions of the Software. 115 | 116 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 117 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 118 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 119 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 120 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 121 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 122 | THE SOFTWARE. 123 | 124 | 125 | @octokit/graphql 126 | MIT 127 | The MIT License 128 | 129 | Copyright (c) 2018 Octokit contributors 130 | 131 | Permission is hereby granted, free of charge, to any person obtaining a copy 132 | of this software and associated documentation files (the "Software"), to deal 133 | in the Software without restriction, including without limitation the rights 134 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 135 | copies of the Software, and to permit persons to whom the Software is 136 | furnished to do so, subject to the following conditions: 137 | 138 | The above copyright notice and this permission notice shall be included in 139 | all copies or substantial portions of the Software. 140 | 141 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 142 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 143 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 144 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 145 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 146 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 147 | THE SOFTWARE. 148 | 149 | 150 | @octokit/plugin-paginate-rest 151 | MIT 152 | MIT License Copyright (c) 2019 Octokit contributors 153 | 154 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 155 | 156 | The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software. 157 | 158 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 159 | 160 | 161 | @octokit/plugin-rest-endpoint-methods 162 | MIT 163 | MIT License Copyright (c) 2019 Octokit contributors 164 | 165 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 166 | 167 | The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software. 168 | 169 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 170 | 171 | 172 | @octokit/request 173 | MIT 174 | The MIT License 175 | 176 | Copyright (c) 2018 Octokit contributors 177 | 178 | Permission is hereby granted, free of charge, to any person obtaining a copy 179 | of this software and associated documentation files (the "Software"), to deal 180 | in the Software without restriction, including without limitation the rights 181 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 182 | copies of the Software, and to permit persons to whom the Software is 183 | furnished to do so, subject to the following conditions: 184 | 185 | The above copyright notice and this permission notice shall be included in 186 | all copies or substantial portions of the Software. 187 | 188 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 189 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 190 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 191 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 192 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 193 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 194 | THE SOFTWARE. 195 | 196 | 197 | @octokit/request-error 198 | MIT 199 | The MIT License 200 | 201 | Copyright (c) 2019 Octokit contributors 202 | 203 | Permission is hereby granted, free of charge, to any person obtaining a copy 204 | of this software and associated documentation files (the "Software"), to deal 205 | in the Software without restriction, including without limitation the rights 206 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 207 | copies of the Software, and to permit persons to whom the Software is 208 | furnished to do so, subject to the following conditions: 209 | 210 | The above copyright notice and this permission notice shall be included in 211 | all copies or substantial portions of the Software. 212 | 213 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 214 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 215 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 216 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 217 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 218 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 219 | THE SOFTWARE. 220 | 221 | 222 | before-after-hook 223 | Apache-2.0 224 | Apache License 225 | Version 2.0, January 2004 226 | http://www.apache.org/licenses/ 227 | 228 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 229 | 230 | 1. Definitions. 231 | 232 | "License" shall mean the terms and conditions for use, reproduction, 233 | and distribution as defined by Sections 1 through 9 of this document. 234 | 235 | "Licensor" shall mean the copyright owner or entity authorized by 236 | the copyright owner that is granting the License. 237 | 238 | "Legal Entity" shall mean the union of the acting entity and all 239 | other entities that control, are controlled by, or are under common 240 | control with that entity. For the purposes of this definition, 241 | "control" means (i) the power, direct or indirect, to cause the 242 | direction or management of such entity, whether by contract or 243 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 244 | outstanding shares, or (iii) beneficial ownership of such entity. 245 | 246 | "You" (or "Your") shall mean an individual or Legal Entity 247 | exercising permissions granted by this License. 248 | 249 | "Source" form shall mean the preferred form for making modifications, 250 | including but not limited to software source code, documentation 251 | source, and configuration files. 252 | 253 | "Object" form shall mean any form resulting from mechanical 254 | transformation or translation of a Source form, including but 255 | not limited to compiled object code, generated documentation, 256 | and conversions to other media types. 257 | 258 | "Work" shall mean the work of authorship, whether in Source or 259 | Object form, made available under the License, as indicated by a 260 | copyright notice that is included in or attached to the work 261 | (an example is provided in the Appendix below). 262 | 263 | "Derivative Works" shall mean any work, whether in Source or Object 264 | form, that is based on (or derived from) the Work and for which the 265 | editorial revisions, annotations, elaborations, or other modifications 266 | represent, as a whole, an original work of authorship. For the purposes 267 | of this License, Derivative Works shall not include works that remain 268 | separable from, or merely link (or bind by name) to the interfaces of, 269 | the Work and Derivative Works thereof. 270 | 271 | "Contribution" shall mean any work of authorship, including 272 | the original version of the Work and any modifications or additions 273 | to that Work or Derivative Works thereof, that is intentionally 274 | submitted to Licensor for inclusion in the Work by the copyright owner 275 | or by an individual or Legal Entity authorized to submit on behalf of 276 | the copyright owner. For the purposes of this definition, "submitted" 277 | means any form of electronic, verbal, or written communication sent 278 | to the Licensor or its representatives, including but not limited to 279 | communication on electronic mailing lists, source code control systems, 280 | and issue tracking systems that are managed by, or on behalf of, the 281 | Licensor for the purpose of discussing and improving the Work, but 282 | excluding communication that is conspicuously marked or otherwise 283 | designated in writing by the copyright owner as "Not a Contribution." 284 | 285 | "Contributor" shall mean Licensor and any individual or Legal Entity 286 | on behalf of whom a Contribution has been received by Licensor and 287 | subsequently incorporated within the Work. 288 | 289 | 2. Grant of Copyright License. Subject to the terms and conditions of 290 | this License, each Contributor hereby grants to You a perpetual, 291 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 292 | copyright license to reproduce, prepare Derivative Works of, 293 | publicly display, publicly perform, sublicense, and distribute the 294 | Work and such Derivative Works in Source or Object form. 295 | 296 | 3. Grant of Patent License. Subject to the terms and conditions of 297 | this License, each Contributor hereby grants to You a perpetual, 298 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 299 | (except as stated in this section) patent license to make, have made, 300 | use, offer to sell, sell, import, and otherwise transfer the Work, 301 | where such license applies only to those patent claims licensable 302 | by such Contributor that are necessarily infringed by their 303 | Contribution(s) alone or by combination of their Contribution(s) 304 | with the Work to which such Contribution(s) was submitted. If You 305 | institute patent litigation against any entity (including a 306 | cross-claim or counterclaim in a lawsuit) alleging that the Work 307 | or a Contribution incorporated within the Work constitutes direct 308 | or contributory patent infringement, then any patent licenses 309 | granted to You under this License for that Work shall terminate 310 | as of the date such litigation is filed. 311 | 312 | 4. Redistribution. You may reproduce and distribute copies of the 313 | Work or Derivative Works thereof in any medium, with or without 314 | modifications, and in Source or Object form, provided that You 315 | meet the following conditions: 316 | 317 | (a) You must give any other recipients of the Work or 318 | Derivative Works a copy of this License; and 319 | 320 | (b) You must cause any modified files to carry prominent notices 321 | stating that You changed the files; and 322 | 323 | (c) You must retain, in the Source form of any Derivative Works 324 | that You distribute, all copyright, patent, trademark, and 325 | attribution notices from the Source form of the Work, 326 | excluding those notices that do not pertain to any part of 327 | the Derivative Works; and 328 | 329 | (d) If the Work includes a "NOTICE" text file as part of its 330 | distribution, then any Derivative Works that You distribute must 331 | include a readable copy of the attribution notices contained 332 | within such NOTICE file, excluding those notices that do not 333 | pertain to any part of the Derivative Works, in at least one 334 | of the following places: within a NOTICE text file distributed 335 | as part of the Derivative Works; within the Source form or 336 | documentation, if provided along with the Derivative Works; or, 337 | within a display generated by the Derivative Works, if and 338 | wherever such third-party notices normally appear. The contents 339 | of the NOTICE file are for informational purposes only and 340 | do not modify the License. You may add Your own attribution 341 | notices within Derivative Works that You distribute, alongside 342 | or as an addendum to the NOTICE text from the Work, provided 343 | that such additional attribution notices cannot be construed 344 | as modifying the License. 345 | 346 | You may add Your own copyright statement to Your modifications and 347 | may provide additional or different license terms and conditions 348 | for use, reproduction, or distribution of Your modifications, or 349 | for any such Derivative Works as a whole, provided Your use, 350 | reproduction, and distribution of the Work otherwise complies with 351 | the conditions stated in this License. 352 | 353 | 5. Submission of Contributions. Unless You explicitly state otherwise, 354 | any Contribution intentionally submitted for inclusion in the Work 355 | by You to the Licensor shall be under the terms and conditions of 356 | this License, without any additional terms or conditions. 357 | Notwithstanding the above, nothing herein shall supersede or modify 358 | the terms of any separate license agreement you may have executed 359 | with Licensor regarding such Contributions. 360 | 361 | 6. Trademarks. This License does not grant permission to use the trade 362 | names, trademarks, service marks, or product names of the Licensor, 363 | except as required for reasonable and customary use in describing the 364 | origin of the Work and reproducing the content of the NOTICE file. 365 | 366 | 7. Disclaimer of Warranty. Unless required by applicable law or 367 | agreed to in writing, Licensor provides the Work (and each 368 | Contributor provides its Contributions) on an "AS IS" BASIS, 369 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 370 | implied, including, without limitation, any warranties or conditions 371 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 372 | PARTICULAR PURPOSE. You are solely responsible for determining the 373 | appropriateness of using or redistributing the Work and assume any 374 | risks associated with Your exercise of permissions under this License. 375 | 376 | 8. Limitation of Liability. In no event and under no legal theory, 377 | whether in tort (including negligence), contract, or otherwise, 378 | unless required by applicable law (such as deliberate and grossly 379 | negligent acts) or agreed to in writing, shall any Contributor be 380 | liable to You for damages, including any direct, indirect, special, 381 | incidental, or consequential damages of any character arising as a 382 | result of this License or out of the use or inability to use the 383 | Work (including but not limited to damages for loss of goodwill, 384 | work stoppage, computer failure or malfunction, or any and all 385 | other commercial damages or losses), even if such Contributor 386 | has been advised of the possibility of such damages. 387 | 388 | 9. Accepting Warranty or Additional Liability. While redistributing 389 | the Work or Derivative Works thereof, You may choose to offer, 390 | and charge a fee for, acceptance of support, warranty, indemnity, 391 | or other liability obligations and/or rights consistent with this 392 | License. However, in accepting such obligations, You may act only 393 | on Your own behalf and on Your sole responsibility, not on behalf 394 | of any other Contributor, and only if You agree to indemnify, 395 | defend, and hold each Contributor harmless for any liability 396 | incurred by, or claims asserted against, such Contributor by reason 397 | of your accepting any such warranty or additional liability. 398 | 399 | END OF TERMS AND CONDITIONS 400 | 401 | APPENDIX: How to apply the Apache License to your work. 402 | 403 | To apply the Apache License to your work, attach the following 404 | boilerplate notice, with the fields enclosed by brackets "{}" 405 | replaced with your own identifying information. (Don't include 406 | the brackets!) The text should be enclosed in the appropriate 407 | comment syntax for the file format. We also recommend that a 408 | file or class name and description of purpose be included on the 409 | same "printed page" as the copyright notice for easier 410 | identification within third-party archives. 411 | 412 | Copyright 2018 Gregor Martynus and other contributors. 413 | 414 | Licensed under the Apache License, Version 2.0 (the "License"); 415 | you may not use this file except in compliance with the License. 416 | You may obtain a copy of the License at 417 | 418 | http://www.apache.org/licenses/LICENSE-2.0 419 | 420 | Unless required by applicable law or agreed to in writing, software 421 | distributed under the License is distributed on an "AS IS" BASIS, 422 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 423 | See the License for the specific language governing permissions and 424 | limitations under the License. 425 | 426 | 427 | deprecation 428 | ISC 429 | The ISC License 430 | 431 | Copyright (c) Gregor Martynus and contributors 432 | 433 | Permission to use, copy, modify, and/or distribute this software for any 434 | purpose with or without fee is hereby granted, provided that the above 435 | copyright notice and this permission notice appear in all copies. 436 | 437 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 438 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 439 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 440 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 441 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 442 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 443 | IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 444 | 445 | 446 | encoding 447 | MIT 448 | Copyright (c) 2012-2014 Andris Reinman 449 | 450 | Permission is hereby granted, free of charge, to any person obtaining a copy 451 | of this software and associated documentation files (the "Software"), to deal 452 | in the Software without restriction, including without limitation the rights 453 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 454 | copies of the Software, and to permit persons to whom the Software is 455 | furnished to do so, subject to the following conditions: 456 | 457 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 458 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 459 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 460 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 461 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 462 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 463 | SOFTWARE. 464 | 465 | 466 | iconv-lite 467 | MIT 468 | Copyright (c) 2011 Alexander Shtuchkin 469 | 470 | Permission is hereby granted, free of charge, to any person obtaining 471 | a copy of this software and associated documentation files (the 472 | "Software"), to deal in the Software without restriction, including 473 | without limitation the rights to use, copy, modify, merge, publish, 474 | distribute, sublicense, and/or sell copies of the Software, and to 475 | permit persons to whom the Software is furnished to do so, subject to 476 | the following conditions: 477 | 478 | The above copyright notice and this permission notice shall be 479 | included in all copies or substantial portions of the Software. 480 | 481 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 482 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 483 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 484 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 485 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 486 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 487 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 488 | 489 | 490 | 491 | is-plain-object 492 | MIT 493 | The MIT License (MIT) 494 | 495 | Copyright (c) 2014-2017, Jon Schlinkert. 496 | 497 | Permission is hereby granted, free of charge, to any person obtaining a copy 498 | of this software and associated documentation files (the "Software"), to deal 499 | in the Software without restriction, including without limitation the rights 500 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 501 | copies of the Software, and to permit persons to whom the Software is 502 | furnished to do so, subject to the following conditions: 503 | 504 | The above copyright notice and this permission notice shall be included in 505 | all copies or substantial portions of the Software. 506 | 507 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 508 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 509 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 510 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 511 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 512 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 513 | THE SOFTWARE. 514 | 515 | 516 | node-fetch 517 | MIT 518 | The MIT License (MIT) 519 | 520 | Copyright (c) 2016 David Frank 521 | 522 | Permission is hereby granted, free of charge, to any person obtaining a copy 523 | of this software and associated documentation files (the "Software"), to deal 524 | in the Software without restriction, including without limitation the rights 525 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 526 | copies of the Software, and to permit persons to whom the Software is 527 | furnished to do so, subject to the following conditions: 528 | 529 | The above copyright notice and this permission notice shall be included in all 530 | copies or substantial portions of the Software. 531 | 532 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 533 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 534 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 535 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 536 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 537 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 538 | SOFTWARE. 539 | 540 | 541 | 542 | once 543 | ISC 544 | The ISC License 545 | 546 | Copyright (c) Isaac Z. Schlueter and Contributors 547 | 548 | Permission to use, copy, modify, and/or distribute this software for any 549 | purpose with or without fee is hereby granted, provided that the above 550 | copyright notice and this permission notice appear in all copies. 551 | 552 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 553 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 554 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 555 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 556 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 557 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 558 | IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 559 | 560 | 561 | safer-buffer 562 | MIT 563 | MIT License 564 | 565 | Copyright (c) 2018 Nikita Skovoroda 566 | 567 | Permission is hereby granted, free of charge, to any person obtaining a copy 568 | of this software and associated documentation files (the "Software"), to deal 569 | in the Software without restriction, including without limitation the rights 570 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 571 | copies of the Software, and to permit persons to whom the Software is 572 | furnished to do so, subject to the following conditions: 573 | 574 | The above copyright notice and this permission notice shall be included in all 575 | copies or substantial portions of the Software. 576 | 577 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 578 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 579 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 580 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 581 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 582 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 583 | SOFTWARE. 584 | 585 | 586 | tr46 587 | MIT 588 | 589 | tunnel 590 | MIT 591 | The MIT License (MIT) 592 | 593 | Copyright (c) 2012 Koichi Kobayashi 594 | 595 | Permission is hereby granted, free of charge, to any person obtaining a copy 596 | of this software and associated documentation files (the "Software"), to deal 597 | in the Software without restriction, including without limitation the rights 598 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 599 | copies of the Software, and to permit persons to whom the Software is 600 | furnished to do so, subject to the following conditions: 601 | 602 | The above copyright notice and this permission notice shall be included in 603 | all copies or substantial portions of the Software. 604 | 605 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 606 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 607 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 608 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 609 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 610 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 611 | THE SOFTWARE. 612 | 613 | 614 | universal-user-agent 615 | ISC 616 | # [ISC License](https://spdx.org/licenses/ISC) 617 | 618 | Copyright (c) 2018, Gregor Martynus (https://github.com/gr2m) 619 | 620 | Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. 621 | 622 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 623 | 624 | 625 | uuid 626 | MIT 627 | The MIT License (MIT) 628 | 629 | Copyright (c) 2010-2020 Robert Kieffer and other contributors 630 | 631 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 632 | 633 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 634 | 635 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 636 | 637 | 638 | webidl-conversions 639 | BSD-2-Clause 640 | # The BSD 2-Clause License 641 | 642 | Copyright (c) 2014, Domenic Denicola 643 | All rights reserved. 644 | 645 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 646 | 647 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 648 | 649 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 650 | 651 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 652 | 653 | 654 | whatwg-url 655 | MIT 656 | The MIT License (MIT) 657 | 658 | Copyright (c) 2015–2016 Sebastian Mayr 659 | 660 | Permission is hereby granted, free of charge, to any person obtaining a copy 661 | of this software and associated documentation files (the "Software"), to deal 662 | in the Software without restriction, including without limitation the rights 663 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 664 | copies of the Software, and to permit persons to whom the Software is 665 | furnished to do so, subject to the following conditions: 666 | 667 | The above copyright notice and this permission notice shall be included in 668 | all copies or substantial portions of the Software. 669 | 670 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 671 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 672 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 673 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 674 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 675 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 676 | THE SOFTWARE. 677 | 678 | 679 | wrappy 680 | ISC 681 | The ISC License 682 | 683 | Copyright (c) Isaac Z. Schlueter and Contributors 684 | 685 | Permission to use, copy, modify, and/or distribute this software for any 686 | purpose with or without fee is hereby granted, provided that the above 687 | copyright notice and this permission notice appear in all copies. 688 | 689 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 690 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 691 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 692 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 693 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 694 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 695 | IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 696 | -------------------------------------------------------------------------------- /test-data/tf_nochanges.json: -------------------------------------------------------------------------------- 1 | { 2 | "format_version": "1.0", 3 | "terraform_version": "1.1.5", 4 | "planned_values": { 5 | "outputs": { 6 | "tls_private_key": { 7 | "sensitive": true 8 | } 9 | }, 10 | "root_module": { 11 | "resources": [ 12 | { 13 | "address": "azurerm_linux_virtual_machine.calvinvm", 14 | "mode": "managed", 15 | "type": "azurerm_linux_virtual_machine", 16 | "name": "calvinvm", 17 | "provider_name": "registry.terraform.io/hashicorp/azurerm", 18 | "schema_version": 0, 19 | "values": { 20 | "additional_capabilities": [], 21 | "admin_password": null, 22 | "admin_ssh_key": [ 23 | { 24 | "username": "azureuser" 25 | } 26 | ], 27 | "admin_username": "azureuser", 28 | "allow_extension_operations": true, 29 | "availability_set_id": null, 30 | "boot_diagnostics": [ 31 | {} 32 | ], 33 | "computer_name": "calvintestvm", 34 | "custom_data": null, 35 | "dedicated_host_group_id": null, 36 | "dedicated_host_id": null, 37 | "disable_password_authentication": true, 38 | "encryption_at_host_enabled": null, 39 | "eviction_policy": null, 40 | "extensions_time_budget": "PT1H30M", 41 | "identity": [], 42 | "license_type": null, 43 | "location": "centralus", 44 | "max_bid_price": -1, 45 | "name": "calvinVM", 46 | "os_disk": [ 47 | { 48 | "caching": "ReadWrite", 49 | "diff_disk_settings": [], 50 | "disk_encryption_set_id": null, 51 | "name": "calvinOsDisk", 52 | "storage_account_type": "Standard_LRS", 53 | "write_accelerator_enabled": false 54 | } 55 | ], 56 | "patch_mode": "ImageDefault", 57 | "plan": [], 58 | "platform_fault_domain": -1, 59 | "priority": "Regular", 60 | "provision_vm_agent": true, 61 | "proximity_placement_group_id": null, 62 | "resource_group_name": "calvin-experimenting", 63 | "secret": [], 64 | "secure_boot_enabled": null, 65 | "size": "Standard_DS1_v2", 66 | "source_image_id": null, 67 | "source_image_reference": [ 68 | { 69 | "offer": "UbuntuServer", 70 | "publisher": "Canonical", 71 | "sku": "18.04-LTS", 72 | "version": "latest" 73 | } 74 | ], 75 | "tags": { 76 | "project": "calvin-experimenting" 77 | }, 78 | "timeouts": null, 79 | "user_data": null, 80 | "virtual_machine_scale_set_id": null, 81 | "vtpm_enabled": null 82 | }, 83 | "sensitive_values": { 84 | "additional_capabilities": [], 85 | "admin_ssh_key": [ 86 | {} 87 | ], 88 | "boot_diagnostics": [ 89 | {} 90 | ], 91 | "identity": [], 92 | "network_interface_ids": [], 93 | "os_disk": [ 94 | { 95 | "diff_disk_settings": [] 96 | } 97 | ], 98 | "plan": [], 99 | "private_ip_addresses": [], 100 | "public_ip_addresses": [], 101 | "secret": [], 102 | "source_image_reference": [ 103 | {} 104 | ], 105 | "tags": {} 106 | } 107 | }, 108 | { 109 | "address": "azurerm_network_interface.calvin-nic", 110 | "mode": "managed", 111 | "type": "azurerm_network_interface", 112 | "name": "calvin-nic", 113 | "provider_name": "registry.terraform.io/hashicorp/azurerm", 114 | "schema_version": 0, 115 | "values": { 116 | "enable_accelerated_networking": false, 117 | "enable_ip_forwarding": false, 118 | "ip_configuration": [ 119 | { 120 | "name": "calvinNicConfiguration", 121 | "private_ip_address_allocation": "dynamic", 122 | "private_ip_address_version": "IPv4" 123 | } 124 | ], 125 | "location": "centralus", 126 | "name": "calvinNICtest", 127 | "resource_group_name": "calvin-experimenting", 128 | "tags": { 129 | "project": "calvin-experimenting" 130 | }, 131 | "timeouts": null 132 | }, 133 | "sensitive_values": { 134 | "applied_dns_servers": [], 135 | "dns_servers": [], 136 | "ip_configuration": [ 137 | {} 138 | ], 139 | "private_ip_addresses": [], 140 | "tags": {} 141 | } 142 | }, 143 | { 144 | "address": "azurerm_network_interface_security_group_association.calvin-sg-nic", 145 | "mode": "managed", 146 | "type": "azurerm_network_interface_security_group_association", 147 | "name": "calvin-sg-nic", 148 | "provider_name": "registry.terraform.io/hashicorp/azurerm", 149 | "schema_version": 0, 150 | "values": { 151 | "timeouts": null 152 | }, 153 | "sensitive_values": {} 154 | }, 155 | { 156 | "address": "azurerm_network_security_group.calvin-security-group", 157 | "mode": "managed", 158 | "type": "azurerm_network_security_group", 159 | "name": "calvin-security-group", 160 | "provider_name": "registry.terraform.io/hashicorp/azurerm", 161 | "schema_version": 0, 162 | "values": { 163 | "location": "centralus", 164 | "name": "calvinsg", 165 | "resource_group_name": "calvin-experimenting", 166 | "security_rule": [ 167 | { 168 | "access": "Allow", 169 | "description": "", 170 | "destination_address_prefix": "*", 171 | "destination_address_prefixes": [], 172 | "destination_application_security_group_ids": [], 173 | "destination_port_range": "22", 174 | "destination_port_ranges": [], 175 | "direction": "Inbound", 176 | "name": "SSH", 177 | "priority": 1001, 178 | "protocol": "Tcp", 179 | "source_address_prefix": "*", 180 | "source_address_prefixes": [], 181 | "source_application_security_group_ids": [], 182 | "source_port_range": "*", 183 | "source_port_ranges": [] 184 | } 185 | ], 186 | "tags": { 187 | "project": "calvin-experimenting" 188 | }, 189 | "timeouts": null 190 | }, 191 | "sensitive_values": { 192 | "security_rule": [ 193 | { 194 | "destination_address_prefixes": [], 195 | "destination_application_security_group_ids": [], 196 | "destination_port_ranges": [], 197 | "source_address_prefixes": [], 198 | "source_application_security_group_ids": [], 199 | "source_port_ranges": [] 200 | } 201 | ], 202 | "tags": {} 203 | } 204 | }, 205 | { 206 | "address": "azurerm_public_ip.calvin-ip", 207 | "mode": "managed", 208 | "type": "azurerm_public_ip", 209 | "name": "calvin-ip", 210 | "provider_name": "registry.terraform.io/hashicorp/azurerm", 211 | "schema_version": 0, 212 | "values": { 213 | "allocation_method": "Dynamic", 214 | "domain_name_label": null, 215 | "idle_timeout_in_minutes": 4, 216 | "ip_tags": null, 217 | "ip_version": "IPv4", 218 | "location": "centralus", 219 | "name": "calvinpublicip", 220 | "public_ip_prefix_id": null, 221 | "resource_group_name": "calvin-experimenting", 222 | "reverse_fqdn": null, 223 | "sku": "Basic", 224 | "sku_tier": "Regional", 225 | "tags": { 226 | "project": "calvin-experimenting" 227 | }, 228 | "timeouts": null 229 | }, 230 | "sensitive_values": { 231 | "tags": {}, 232 | "zones": [] 233 | } 234 | }, 235 | { 236 | "address": "azurerm_resource_group.calvin", 237 | "mode": "managed", 238 | "type": "azurerm_resource_group", 239 | "name": "calvin", 240 | "provider_name": "registry.terraform.io/hashicorp/azurerm", 241 | "schema_version": 0, 242 | "values": { 243 | "location": "centralus", 244 | "name": "calvin-experimenting", 245 | "tags": null, 246 | "timeouts": null 247 | }, 248 | "sensitive_values": {} 249 | }, 250 | { 251 | "address": "azurerm_storage_account.calvin-sa", 252 | "mode": "managed", 253 | "type": "azurerm_storage_account", 254 | "name": "calvin-sa", 255 | "provider_name": "registry.terraform.io/hashicorp/azurerm", 256 | "schema_version": 2, 257 | "values": { 258 | "account_kind": "StorageV2", 259 | "account_replication_type": "LRS", 260 | "account_tier": "Standard", 261 | "allow_blob_public_access": false, 262 | "azure_files_authentication": [], 263 | "custom_domain": [], 264 | "enable_https_traffic_only": true, 265 | "identity": [], 266 | "infrastructure_encryption_enabled": false, 267 | "is_hns_enabled": false, 268 | "location": "centralus", 269 | "min_tls_version": "TLS1_0", 270 | "nfsv3_enabled": false, 271 | "queue_encryption_key_type": "Service", 272 | "resource_group_name": "calvin-experimenting", 273 | "shared_access_key_enabled": true, 274 | "static_website": [], 275 | "table_encryption_key_type": "Service", 276 | "tags": { 277 | "project": "calvin-experimenting" 278 | }, 279 | "timeouts": null 280 | }, 281 | "sensitive_values": { 282 | "azure_files_authentication": [], 283 | "blob_properties": [], 284 | "custom_domain": [], 285 | "identity": [], 286 | "network_rules": [], 287 | "queue_properties": [], 288 | "routing": [], 289 | "share_properties": [], 290 | "static_website": [], 291 | "tags": {} 292 | } 293 | }, 294 | { 295 | "address": "azurerm_subnet.calvin-subnet", 296 | "mode": "managed", 297 | "type": "azurerm_subnet", 298 | "name": "calvin-subnet", 299 | "provider_name": "registry.terraform.io/hashicorp/azurerm", 300 | "schema_version": 0, 301 | "values": { 302 | "address_prefixes": [ 303 | "10.0.1.0/24" 304 | ], 305 | "delegation": [], 306 | "enforce_private_link_endpoint_network_policies": false, 307 | "enforce_private_link_service_network_policies": false, 308 | "name": "calvinsubnettest", 309 | "resource_group_name": "calvin-experimenting", 310 | "service_endpoint_policy_ids": null, 311 | "service_endpoints": null, 312 | "timeouts": null, 313 | "virtual_network_name": "calvinvnettest" 314 | }, 315 | "sensitive_values": { 316 | "address_prefixes": [ 317 | false 318 | ], 319 | "delegation": [] 320 | } 321 | }, 322 | { 323 | "address": "azurerm_virtual_network.calvin-vn", 324 | "mode": "managed", 325 | "type": "azurerm_virtual_network", 326 | "name": "calvin-vn", 327 | "provider_name": "registry.terraform.io/hashicorp/azurerm", 328 | "schema_version": 0, 329 | "values": { 330 | "address_space": [ 331 | "10.0.0.0/16" 332 | ], 333 | "bgp_community": null, 334 | "ddos_protection_plan": [], 335 | "flow_timeout_in_minutes": null, 336 | "location": "centralus", 337 | "name": "calvinvnettest", 338 | "resource_group_name": "calvin-experimenting", 339 | "tags": { 340 | "project": "calvin-experimenting" 341 | }, 342 | "timeouts": null, 343 | "vm_protection_enabled": false 344 | }, 345 | "sensitive_values": { 346 | "address_space": [ 347 | false 348 | ], 349 | "ddos_protection_plan": [], 350 | "dns_servers": [], 351 | "subnet": [], 352 | "tags": {} 353 | } 354 | }, 355 | { 356 | "address": "random_id.calvin-rid", 357 | "mode": "managed", 358 | "type": "random_id", 359 | "name": "calvin-rid", 360 | "provider_name": "registry.terraform.io/hashicorp/random", 361 | "schema_version": 0, 362 | "values": { 363 | "byte_length": 8, 364 | "keepers": { 365 | "resource_group": "calvin-experimenting" 366 | }, 367 | "prefix": null 368 | }, 369 | "sensitive_values": { 370 | "keepers": {} 371 | } 372 | }, 373 | { 374 | "address": "tls_private_key.calvin_ssh", 375 | "mode": "managed", 376 | "type": "tls_private_key", 377 | "name": "calvin_ssh", 378 | "provider_name": "registry.terraform.io/hashicorp/tls", 379 | "schema_version": 0, 380 | "values": { 381 | "algorithm": "RSA", 382 | "ecdsa_curve": "P224", 383 | "rsa_bits": 4096 384 | }, 385 | "sensitive_values": {} 386 | } 387 | ] 388 | } 389 | }, 390 | "resource_changes": [], 391 | "output_changes": {}, 392 | "configuration": { 393 | "provider_config": { 394 | "azurerm": { 395 | "name": "azurerm", 396 | "version_constraint": "2.95.0", 397 | "expressions": { 398 | "features": [ 399 | {} 400 | ] 401 | } 402 | } 403 | }, 404 | "root_module": { 405 | "outputs": { 406 | "tls_private_key": { 407 | "sensitive": true, 408 | "expression": { 409 | "references": [ 410 | "tls_private_key.calvin_ssh.private_key_pem", 411 | "tls_private_key.calvin_ssh" 412 | ] 413 | } 414 | } 415 | }, 416 | "resources": [ 417 | { 418 | "address": "azurerm_linux_virtual_machine.calvinvm", 419 | "mode": "managed", 420 | "type": "azurerm_linux_virtual_machine", 421 | "name": "calvinvm", 422 | "provider_config_key": "azurerm", 423 | "expressions": { 424 | "admin_ssh_key": [ 425 | { 426 | "public_key": { 427 | "references": [ 428 | "tls_private_key.calvin_ssh.public_key_openssh", 429 | "tls_private_key.calvin_ssh" 430 | ] 431 | }, 432 | "username": { 433 | "constant_value": "azureuser" 434 | } 435 | } 436 | ], 437 | "admin_username": { 438 | "constant_value": "azureuser" 439 | }, 440 | "boot_diagnostics": [ 441 | { 442 | "storage_account_uri": { 443 | "references": [ 444 | "azurerm_storage_account.calvin-sa.primary_blob_endpoint", 445 | "azurerm_storage_account.calvin-sa" 446 | ] 447 | } 448 | } 449 | ], 450 | "computer_name": { 451 | "constant_value": "calvintestvm" 452 | }, 453 | "disable_password_authentication": { 454 | "constant_value": true 455 | }, 456 | "location": { 457 | "references": [ 458 | "azurerm_resource_group.calvin.location", 459 | "azurerm_resource_group.calvin" 460 | ] 461 | }, 462 | "name": { 463 | "constant_value": "calvinVM" 464 | }, 465 | "network_interface_ids": { 466 | "references": [ 467 | "azurerm_network_interface.calvin-nic.id", 468 | "azurerm_network_interface.calvin-nic" 469 | ] 470 | }, 471 | "os_disk": [ 472 | { 473 | "caching": { 474 | "constant_value": "ReadWrite" 475 | }, 476 | "name": { 477 | "constant_value": "calvinOsDisk" 478 | }, 479 | "storage_account_type": { 480 | "constant_value": "Standard_LRS" 481 | } 482 | } 483 | ], 484 | "resource_group_name": { 485 | "references": [ 486 | "azurerm_resource_group.calvin.name", 487 | "azurerm_resource_group.calvin" 488 | ] 489 | }, 490 | "size": { 491 | "constant_value": "Standard_DS1_v2" 492 | }, 493 | "source_image_reference": [ 494 | { 495 | "offer": { 496 | "constant_value": "UbuntuServer" 497 | }, 498 | "publisher": { 499 | "constant_value": "Canonical" 500 | }, 501 | "sku": { 502 | "constant_value": "18.04-LTS" 503 | }, 504 | "version": { 505 | "constant_value": "latest" 506 | } 507 | } 508 | ], 509 | "tags": { 510 | "constant_value": { 511 | "project": "calvin-experimenting" 512 | } 513 | } 514 | }, 515 | "schema_version": 0 516 | }, 517 | { 518 | "address": "azurerm_network_interface.calvin-nic", 519 | "mode": "managed", 520 | "type": "azurerm_network_interface", 521 | "name": "calvin-nic", 522 | "provider_config_key": "azurerm", 523 | "expressions": { 524 | "ip_configuration": [ 525 | { 526 | "name": { 527 | "constant_value": "calvinNicConfiguration" 528 | }, 529 | "private_ip_address_allocation": { 530 | "constant_value": "Dynamic" 531 | }, 532 | "public_ip_address_id": { 533 | "references": [ 534 | "azurerm_public_ip.calvin-ip.id", 535 | "azurerm_public_ip.calvin-ip" 536 | ] 537 | }, 538 | "subnet_id": { 539 | "references": [ 540 | "azurerm_subnet.calvin-subnet.id", 541 | "azurerm_subnet.calvin-subnet" 542 | ] 543 | } 544 | } 545 | ], 546 | "location": { 547 | "references": [ 548 | "azurerm_resource_group.calvin.location", 549 | "azurerm_resource_group.calvin" 550 | ] 551 | }, 552 | "name": { 553 | "constant_value": "calvinNICtest" 554 | }, 555 | "resource_group_name": { 556 | "references": [ 557 | "azurerm_resource_group.calvin.name", 558 | "azurerm_resource_group.calvin" 559 | ] 560 | }, 561 | "tags": { 562 | "constant_value": { 563 | "project": "calvin-experimenting" 564 | } 565 | } 566 | }, 567 | "schema_version": 0 568 | }, 569 | { 570 | "address": "azurerm_network_interface_security_group_association.calvin-sg-nic", 571 | "mode": "managed", 572 | "type": "azurerm_network_interface_security_group_association", 573 | "name": "calvin-sg-nic", 574 | "provider_config_key": "azurerm", 575 | "expressions": { 576 | "network_interface_id": { 577 | "references": [ 578 | "azurerm_network_interface.calvin-nic.id", 579 | "azurerm_network_interface.calvin-nic" 580 | ] 581 | }, 582 | "network_security_group_id": { 583 | "references": [ 584 | "azurerm_network_security_group.calvin-security-group.id", 585 | "azurerm_network_security_group.calvin-security-group" 586 | ] 587 | } 588 | }, 589 | "schema_version": 0 590 | }, 591 | { 592 | "address": "azurerm_network_security_group.calvin-security-group", 593 | "mode": "managed", 594 | "type": "azurerm_network_security_group", 595 | "name": "calvin-security-group", 596 | "provider_config_key": "azurerm", 597 | "expressions": { 598 | "location": { 599 | "references": [ 600 | "azurerm_resource_group.calvin.location", 601 | "azurerm_resource_group.calvin" 602 | ] 603 | }, 604 | "name": { 605 | "constant_value": "calvinsg" 606 | }, 607 | "resource_group_name": { 608 | "references": [ 609 | "azurerm_resource_group.calvin.name", 610 | "azurerm_resource_group.calvin" 611 | ] 612 | }, 613 | "security_rule": { 614 | "constant_value": [ 615 | { 616 | "access": "Allow", 617 | "description": null, 618 | "destination_address_prefix": "*", 619 | "destination_address_prefixes": null, 620 | "destination_application_security_group_ids": null, 621 | "destination_port_range": "22", 622 | "destination_port_ranges": null, 623 | "direction": "Inbound", 624 | "name": "SSH", 625 | "priority": 1001, 626 | "protocol": "Tcp", 627 | "source_address_prefix": "*", 628 | "source_address_prefixes": null, 629 | "source_application_security_group_ids": null, 630 | "source_port_range": "*", 631 | "source_port_ranges": null 632 | } 633 | ] 634 | }, 635 | "tags": { 636 | "constant_value": { 637 | "project": "calvin-experimenting" 638 | } 639 | } 640 | }, 641 | "schema_version": 0 642 | }, 643 | { 644 | "address": "azurerm_public_ip.calvin-ip", 645 | "mode": "managed", 646 | "type": "azurerm_public_ip", 647 | "name": "calvin-ip", 648 | "provider_config_key": "azurerm", 649 | "expressions": { 650 | "allocation_method": { 651 | "constant_value": "Dynamic" 652 | }, 653 | "location": { 654 | "references": [ 655 | "azurerm_resource_group.calvin.location", 656 | "azurerm_resource_group.calvin" 657 | ] 658 | }, 659 | "name": { 660 | "constant_value": "calvinpublicip" 661 | }, 662 | "resource_group_name": { 663 | "references": [ 664 | "azurerm_resource_group.calvin.name", 665 | "azurerm_resource_group.calvin" 666 | ] 667 | }, 668 | "tags": { 669 | "constant_value": { 670 | "project": "calvin-experimenting" 671 | } 672 | } 673 | }, 674 | "schema_version": 0 675 | }, 676 | { 677 | "address": "azurerm_resource_group.calvin", 678 | "mode": "managed", 679 | "type": "azurerm_resource_group", 680 | "name": "calvin", 681 | "provider_config_key": "azurerm", 682 | "expressions": { 683 | "location": { 684 | "constant_value": "Central US" 685 | }, 686 | "name": { 687 | "constant_value": "calvin-experimenting" 688 | } 689 | }, 690 | "schema_version": 0 691 | }, 692 | { 693 | "address": "azurerm_storage_account.calvin-sa", 694 | "mode": "managed", 695 | "type": "azurerm_storage_account", 696 | "name": "calvin-sa", 697 | "provider_config_key": "azurerm", 698 | "expressions": { 699 | "account_replication_type": { 700 | "constant_value": "LRS" 701 | }, 702 | "account_tier": { 703 | "constant_value": "Standard" 704 | }, 705 | "location": { 706 | "references": [ 707 | "azurerm_resource_group.calvin.location", 708 | "azurerm_resource_group.calvin" 709 | ] 710 | }, 711 | "name": { 712 | "references": [ 713 | "random_id.calvin-rid.hex", 714 | "random_id.calvin-rid" 715 | ] 716 | }, 717 | "resource_group_name": { 718 | "references": [ 719 | "azurerm_resource_group.calvin.name", 720 | "azurerm_resource_group.calvin" 721 | ] 722 | }, 723 | "tags": { 724 | "constant_value": { 725 | "project": "calvin-experimenting" 726 | } 727 | } 728 | }, 729 | "schema_version": 2 730 | }, 731 | { 732 | "address": "azurerm_subnet.calvin-subnet", 733 | "mode": "managed", 734 | "type": "azurerm_subnet", 735 | "name": "calvin-subnet", 736 | "provider_config_key": "azurerm", 737 | "expressions": { 738 | "address_prefixes": { 739 | "constant_value": [ 740 | "10.0.1.0/24" 741 | ] 742 | }, 743 | "name": { 744 | "constant_value": "calvinsubnettest" 745 | }, 746 | "resource_group_name": { 747 | "references": [ 748 | "azurerm_resource_group.calvin.name", 749 | "azurerm_resource_group.calvin" 750 | ] 751 | }, 752 | "virtual_network_name": { 753 | "references": [ 754 | "azurerm_virtual_network.calvin-vn.name", 755 | "azurerm_virtual_network.calvin-vn" 756 | ] 757 | } 758 | }, 759 | "schema_version": 0 760 | }, 761 | { 762 | "address": "azurerm_virtual_network.calvin-vn", 763 | "mode": "managed", 764 | "type": "azurerm_virtual_network", 765 | "name": "calvin-vn", 766 | "provider_config_key": "azurerm", 767 | "expressions": { 768 | "address_space": { 769 | "constant_value": [ 770 | "10.0.0.0/16" 771 | ] 772 | }, 773 | "location": { 774 | "constant_value": "Central US" 775 | }, 776 | "name": { 777 | "constant_value": "calvinvnettest" 778 | }, 779 | "resource_group_name": { 780 | "references": [ 781 | "azurerm_resource_group.calvin.name", 782 | "azurerm_resource_group.calvin" 783 | ] 784 | }, 785 | "tags": { 786 | "constant_value": { 787 | "project": "calvin-experimenting" 788 | } 789 | } 790 | }, 791 | "schema_version": 0 792 | }, 793 | { 794 | "address": "random_id.calvin-rid", 795 | "mode": "managed", 796 | "type": "random_id", 797 | "name": "calvin-rid", 798 | "provider_config_key": "random", 799 | "expressions": { 800 | "byte_length": { 801 | "constant_value": 8 802 | }, 803 | "keepers": { 804 | "references": [ 805 | "azurerm_resource_group.calvin.name", 806 | "azurerm_resource_group.calvin" 807 | ] 808 | } 809 | }, 810 | "schema_version": 0 811 | }, 812 | { 813 | "address": "tls_private_key.calvin_ssh", 814 | "mode": "managed", 815 | "type": "tls_private_key", 816 | "name": "calvin_ssh", 817 | "provider_config_key": "tls", 818 | "expressions": { 819 | "algorithm": { 820 | "constant_value": "RSA" 821 | }, 822 | "rsa_bits": { 823 | "constant_value": 4096 824 | } 825 | }, 826 | "schema_version": 0 827 | } 828 | ] 829 | } 830 | } 831 | } -------------------------------------------------------------------------------- /test-data/tf_test4.json: -------------------------------------------------------------------------------- 1 | { 2 | "format_version": "1.1", 3 | "terraform_version": "1.2.9", 4 | "planned_values": { 5 | "root_module": { 6 | "resources": [ 7 | { 8 | "address": "aws_iam_policy.changed", 9 | "mode": "managed", 10 | "type": "aws_iam_policy", 11 | "name": "changed", 12 | "provider_name": "registry.terraform.io/hashicorp/aws", 13 | "schema_version": 0, 14 | "values": { 15 | "arn": "arn:aws:iam::123456789012:policy/test-policy-change", 16 | "description": "", 17 | "id": "arn:aws:iam::123456789012:policy/test-policy-change", 18 | "name": "test-policy-change", 19 | "name_prefix": "", 20 | "path": "/", 21 | "policy": "{\"Statement\":[{\"Action\":\"s3:*\",\"Effect\":\"Allow\",\"Resource\":\"*\",\"Sid\":\"testdoc\"}],\"Version\":\"2012-10-17\"}", 22 | "policy_id": "ANPAR2DEMO", 23 | "tags": {}, 24 | "tags_all": { 25 | "Source": "demo-aws-test", 26 | "SourceVersion": "27NwiYBI3" 27 | } 28 | }, 29 | "sensitive_values": { 30 | "tags": {}, 31 | "tags_all": {} 32 | } 33 | }, 34 | { 35 | "address": "aws_iam_policy.created", 36 | "mode": "managed", 37 | "type": "aws_iam_policy", 38 | "name": "created", 39 | "provider_name": "registry.terraform.io/hashicorp/aws", 40 | "schema_version": 0, 41 | "values": { 42 | "description": null, 43 | "name": "test-policy-created", 44 | "path": "/", 45 | "policy": "{\"Statement\":[{\"Action\":\"s3:Get*\",\"Effect\":\"Allow\",\"Resource\":\"*\",\"Sid\":\"testdoc\"}],\"Version\":\"2012-10-17\"}", 46 | "tags": null, 47 | "tags_all": { 48 | "Source": "demo-aws-test", 49 | "SourceVersion": "27NwiYBI3" 50 | } 51 | }, 52 | "sensitive_values": { 53 | "tags_all": {} 54 | } 55 | }, 56 | { 57 | "address": "aws_iam_policy.tag_and_change", 58 | "mode": "managed", 59 | "type": "aws_iam_policy", 60 | "name": "tag_and_change", 61 | "provider_name": "registry.terraform.io/hashicorp/aws", 62 | "schema_version": 0, 63 | "values": { 64 | "arn": "arn:aws:iam::123456789012:policy/test-policy-tag-and-change", 65 | "description": "", 66 | "id": "arn:aws:iam::123456789012:policy/test-policy-tag-and-change", 67 | "name": "test-policy-tag-and-change", 68 | "name_prefix": "", 69 | "path": "/", 70 | "policy": "{\"Statement\":[{\"Action\":\"s3:*\",\"Effect\":\"Allow\",\"Resource\":\"*\",\"Sid\":\"testdoc\"}],\"Version\":\"2012-10-17\"}", 71 | "policy_id": "ANPAR2NUVQKSU5XSSXLPG", 72 | "tags": {}, 73 | "tags_all": { 74 | "Source": "demo-aws-test", 75 | "SourceVersion": "27NwiYBI3" 76 | } 77 | }, 78 | "sensitive_values": { 79 | "tags": {}, 80 | "tags_all": {} 81 | } 82 | }, 83 | { 84 | "address": "aws_iam_policy.tag_only", 85 | "mode": "managed", 86 | "type": "aws_iam_policy", 87 | "name": "tag_only", 88 | "provider_name": "registry.terraform.io/hashicorp/aws", 89 | "schema_version": 0, 90 | "values": { 91 | "arn": "arn:aws:iam::123456789012:policy/test-policy-tag-only", 92 | "description": "", 93 | "id": "arn:aws:iam::123456789012:policy/test-policy-tag-only", 94 | "name": "test-policy-tag-only", 95 | "name_prefix": "", 96 | "path": "/", 97 | "policy": "{\"Statement\":[{\"Action\":\"s3:Get*\",\"Effect\":\"Allow\",\"Resource\":\"*\",\"Sid\":\"testdoc\"}],\"Version\":\"2012-10-17\"}", 98 | "policy_id": "ANPAR2NUVQKSYF3ZBGWIM", 99 | "tags": { 100 | "SourceVersion": "27NwiYBI6" 101 | }, 102 | "tags_all": { 103 | "Source": "demo-aws-test", 104 | "SourceVersion": "27NwiYBI6" 105 | } 106 | }, 107 | "sensitive_values": { 108 | "tags": {}, 109 | "tags_all": {} 110 | } 111 | }, 112 | { 113 | "address": "aws_iam_policy.tainted", 114 | "mode": "managed", 115 | "type": "aws_iam_policy", 116 | "name": "tainted", 117 | "provider_name": "registry.terraform.io/hashicorp/aws", 118 | "schema_version": 0, 119 | "values": { 120 | "description": null, 121 | "name": "test-policy-tainted", 122 | "path": "/", 123 | "policy": "{\"Statement\":[{\"Action\":\"s3:Get*\",\"Effect\":\"Allow\",\"Resource\":\"*\",\"Sid\":\"testdoc\"}],\"Version\":\"2012-10-17\"}", 124 | "tags": null, 125 | "tags_all": { 126 | "Source": "demo-aws-test", 127 | "SourceVersion": "27NwiYBI3" 128 | } 129 | }, 130 | "sensitive_values": { 131 | "tags_all": {} 132 | } 133 | }, 134 | { 135 | "address": "aws_iam_policy.unchanged", 136 | "mode": "managed", 137 | "type": "aws_iam_policy", 138 | "name": "unchanged", 139 | "provider_name": "registry.terraform.io/hashicorp/aws", 140 | "schema_version": 0, 141 | "values": { 142 | "arn": "arn:aws:iam::123456789012:policy/test-policy-unchanged", 143 | "description": "", 144 | "id": "arn:aws:iam::123456789012:policy/test-policy-unchanged", 145 | "name": "test-policy-unchanged", 146 | "name_prefix": "", 147 | "path": "/", 148 | "policy": "{\"Statement\":[{\"Action\":\"s3:Get*\",\"Effect\":\"Allow\",\"Resource\":\"*\",\"Sid\":\"testdoc\"}],\"Version\":\"2012-10-17\"}", 149 | "policy_id": "ANPAR2NUVQKSU2IBZAFHO", 150 | "tags": {}, 151 | "tags_all": { 152 | "Source": "demo-aws-test", 153 | "SourceVersion": "27NwiYBI3" 154 | } 155 | }, 156 | "sensitive_values": { 157 | "tags": {}, 158 | "tags_all": {} 159 | } 160 | }, 161 | { 162 | "address": "random_string.version", 163 | "mode": "managed", 164 | "type": "random_string", 165 | "name": "version", 166 | "provider_name": "registry.terraform.io/hashicorp/random", 167 | "schema_version": 2, 168 | "values": { 169 | "id": "27NwiYBI", 170 | "keepers": null, 171 | "length": 8, 172 | "lower": true, 173 | "min_lower": 0, 174 | "min_numeric": 0, 175 | "min_special": 0, 176 | "min_upper": 0, 177 | "number": true, 178 | "numeric": true, 179 | "override_special": null, 180 | "result": "27NwiYBI", 181 | "special": false, 182 | "upper": true 183 | }, 184 | "sensitive_values": {} 185 | } 186 | ] 187 | } 188 | }, 189 | "resource_changes": [ 190 | { 191 | "address": "aws_iam_policy.changed", 192 | "mode": "managed", 193 | "type": "aws_iam_policy", 194 | "name": "changed", 195 | "provider_name": "registry.terraform.io/hashicorp/aws", 196 | "change": { 197 | "actions": [ 198 | "update" 199 | ], 200 | "before": { 201 | "arn": "arn:aws:iam::123456789012:policy/test-policy-change", 202 | "description": "", 203 | "id": "arn:aws:iam::123456789012:policy/test-policy-change", 204 | "name": "test-policy-change", 205 | "name_prefix": "", 206 | "path": "/", 207 | "policy": "{\"Statement\":[{\"Action\":\"s3:Get*\",\"Effect\":\"Allow\",\"Resource\":\"*\",\"Sid\":\"testdoc\"}],\"Version\":\"2012-10-17\"}", 208 | "policy_id": "ANPAR2DEMO", 209 | "tags": {}, 210 | "tags_all": { 211 | "Source": "demo-aws-test", 212 | "SourceVersion": "27NwiYBI3" 213 | } 214 | }, 215 | "after": { 216 | "arn": "arn:aws:iam::123456789012:policy/test-policy-change", 217 | "description": "", 218 | "id": "arn:aws:iam::123456789012:policy/test-policy-change", 219 | "name": "test-policy-change", 220 | "name_prefix": "", 221 | "path": "/", 222 | "policy": "{\"Statement\":[{\"Action\":\"s3:*\",\"Effect\":\"Allow\",\"Resource\":\"*\",\"Sid\":\"testdoc\"}],\"Version\":\"2012-10-17\"}", 223 | "policy_id": "ANPAR2DEMO", 224 | "tags": {}, 225 | "tags_all": { 226 | "Source": "demo-aws-test", 227 | "SourceVersion": "27NwiYBI3" 228 | } 229 | }, 230 | "after_unknown": {}, 231 | "before_sensitive": { 232 | "tags": {}, 233 | "tags_all": {} 234 | }, 235 | "after_sensitive": { 236 | "tags": {}, 237 | "tags_all": {} 238 | } 239 | } 240 | }, 241 | { 242 | "address": "aws_iam_policy.created", 243 | "mode": "managed", 244 | "type": "aws_iam_policy", 245 | "name": "created", 246 | "provider_name": "registry.terraform.io/hashicorp/aws", 247 | "change": { 248 | "actions": [ 249 | "create" 250 | ], 251 | "before": null, 252 | "after": { 253 | "description": null, 254 | "name": "test-policy-created", 255 | "path": "/", 256 | "policy": "{\"Statement\":[{\"Action\":\"s3:Get*\",\"Effect\":\"Allow\",\"Resource\":\"*\",\"Sid\":\"testdoc\"}],\"Version\":\"2012-10-17\"}", 257 | "tags": null, 258 | "tags_all": { 259 | "Source": "demo-aws-test", 260 | "SourceVersion": "27NwiYBI3" 261 | } 262 | }, 263 | "after_unknown": { 264 | "arn": true, 265 | "id": true, 266 | "name_prefix": true, 267 | "policy_id": true, 268 | "tags_all": {} 269 | }, 270 | "before_sensitive": false, 271 | "after_sensitive": { 272 | "tags_all": {} 273 | } 274 | } 275 | }, 276 | { 277 | "address": "aws_iam_policy.destroyed", 278 | "mode": "managed", 279 | "type": "aws_iam_policy", 280 | "name": "destroyed", 281 | "provider_name": "registry.terraform.io/hashicorp/aws", 282 | "change": { 283 | "actions": [ 284 | "delete" 285 | ], 286 | "before": { 287 | "arn": "arn:aws:iam::123456789012:policy/test-policy-destroyed", 288 | "description": "", 289 | "id": "arn:aws:iam::123456789012:policy/test-policy-destroyed", 290 | "name": "test-policy-destroyed", 291 | "name_prefix": "", 292 | "path": "/", 293 | "policy": "{\"Statement\":[{\"Action\":\"s3:Get*\",\"Effect\":\"Allow\",\"Resource\":\"*\",\"Sid\":\"testdoc\"}],\"Version\":\"2012-10-17\"}", 294 | "policy_id": "DEMOLIIFZ3", 295 | "tags": {}, 296 | "tags_all": { 297 | "Source": "demo-aws-test", 298 | "SourceVersion": "27NwiYBI3" 299 | } 300 | }, 301 | "after": null, 302 | "after_unknown": {}, 303 | "before_sensitive": { 304 | "tags": {}, 305 | "tags_all": {} 306 | }, 307 | "after_sensitive": false 308 | }, 309 | "action_reason": "delete_because_no_resource_config" 310 | }, 311 | { 312 | "address": "aws_iam_policy.tag_and_change", 313 | "mode": "managed", 314 | "type": "aws_iam_policy", 315 | "name": "tag_and_change", 316 | "provider_name": "registry.terraform.io/hashicorp/aws", 317 | "change": { 318 | "actions": [ 319 | "update" 320 | ], 321 | "before": { 322 | "arn": "arn:aws:iam::123456789012:policy/test-policy-tag-and-change", 323 | "description": "", 324 | "id": "arn:aws:iam::123456789012:policy/test-policy-tag-and-change", 325 | "name": "test-policy-tag-and-change", 326 | "name_prefix": "", 327 | "path": "/", 328 | "policy": "{\"Statement\":[{\"Action\":\"s3:Get*\",\"Effect\":\"Allow\",\"Resource\":\"*\",\"Sid\":\"testdoc\"}],\"Version\":\"2012-10-17\"}", 329 | "policy_id": "ANPAR2NUVQKSU5XSSXLPG", 330 | "tags": { 331 | "SourceVersion": "27NwiYBI6" 332 | }, 333 | "tags_all": { 334 | "Source": "demo-aws-test", 335 | "SourceVersion": "27NwiYBI6" 336 | } 337 | }, 338 | "after": { 339 | "arn": "arn:aws:iam::123456789012:policy/test-policy-tag-and-change", 340 | "description": "", 341 | "id": "arn:aws:iam::123456789012:policy/test-policy-tag-and-change", 342 | "name": "test-policy-tag-and-change", 343 | "name_prefix": "", 344 | "path": "/", 345 | "policy": "{\"Statement\":[{\"Action\":\"s3:*\",\"Effect\":\"Allow\",\"Resource\":\"*\",\"Sid\":\"testdoc\"}],\"Version\":\"2012-10-17\"}", 346 | "policy_id": "ANPAR2NUVQKSU5XSSXLPG", 347 | "tags": {}, 348 | "tags_all": { 349 | "Source": "demo-aws-test", 350 | "SourceVersion": "27NwiYBI3" 351 | } 352 | }, 353 | "after_unknown": {}, 354 | "before_sensitive": { 355 | "tags": {}, 356 | "tags_all": {} 357 | }, 358 | "after_sensitive": { 359 | "tags": {}, 360 | "tags_all": {} 361 | } 362 | } 363 | }, 364 | { 365 | "address": "aws_iam_policy.tag_only", 366 | "mode": "managed", 367 | "type": "aws_iam_policy", 368 | "name": "tag_only", 369 | "provider_name": "registry.terraform.io/hashicorp/aws", 370 | "change": { 371 | "actions": [ 372 | "update" 373 | ], 374 | "before": { 375 | "arn": "arn:aws:iam::123456789012:policy/test-policy-tag-only", 376 | "description": "", 377 | "id": "arn:aws:iam::123456789012:policy/test-policy-tag-only", 378 | "name": "test-policy-tag-only", 379 | "name_prefix": "", 380 | "path": "/", 381 | "policy": "{\"Statement\":[{\"Action\":\"s3:Get*\",\"Effect\":\"Allow\",\"Resource\":\"*\",\"Sid\":\"testdoc\"}],\"Version\":\"2012-10-17\"}", 382 | "policy_id": "ANPAR2NUVQKSYF3ZBGWIM", 383 | "tags": {}, 384 | "tags_all": { 385 | "Source": "demo-aws-test", 386 | "SourceVersion": "27NwiYBI3" 387 | } 388 | }, 389 | "after": { 390 | "arn": "arn:aws:iam::123456789012:policy/test-policy-tag-only", 391 | "description": "", 392 | "id": "arn:aws:iam::123456789012:policy/test-policy-tag-only", 393 | "name": "test-policy-tag-only", 394 | "name_prefix": "", 395 | "path": "/", 396 | "policy": "{\"Statement\":[{\"Action\":\"s3:Get*\",\"Effect\":\"Allow\",\"Resource\":\"*\",\"Sid\":\"testdoc\"}],\"Version\":\"2012-10-17\"}", 397 | "policy_id": "ANPAR2NUVQKSYF3ZBGWIM", 398 | "tags": { 399 | "SourceVersion": "27NwiYBI6" 400 | }, 401 | "tags_all": { 402 | "Source": "demo-aws-test", 403 | "SourceVersion": "27NwiYBI6" 404 | } 405 | }, 406 | "after_unknown": {}, 407 | "before_sensitive": { 408 | "tags": {}, 409 | "tags_all": {} 410 | }, 411 | "after_sensitive": { 412 | "tags": {}, 413 | "tags_all": {} 414 | } 415 | } 416 | }, 417 | { 418 | "address": "aws_iam_policy.tainted", 419 | "mode": "managed", 420 | "type": "aws_iam_policy", 421 | "name": "tainted", 422 | "provider_name": "registry.terraform.io/hashicorp/aws", 423 | "change": { 424 | "actions": [ 425 | "delete", 426 | "create" 427 | ], 428 | "before": { 429 | "arn": "arn:aws:iam::123456789012:policy/test-policy-tainted", 430 | "description": "", 431 | "id": "arn:aws:iam::123456789012:policy/test-policy-tainted", 432 | "name": "test-policy-tainted", 433 | "name_prefix": "", 434 | "path": "/", 435 | "policy": "{\"Statement\":[{\"Action\":\"s3:Get*\",\"Effect\":\"Allow\",\"Resource\":\"*\",\"Sid\":\"testdoc\"}],\"Version\":\"2012-10-17\"}", 436 | "policy_id": "ANPAR2NUVQKSV46NWXCIW", 437 | "tags": {}, 438 | "tags_all": { 439 | "Source": "demo-aws-test", 440 | "SourceVersion": "27NwiYBI3" 441 | } 442 | }, 443 | "after": { 444 | "description": null, 445 | "name": "test-policy-tainted", 446 | "path": "/", 447 | "policy": "{\"Statement\":[{\"Action\":\"s3:Get*\",\"Effect\":\"Allow\",\"Resource\":\"*\",\"Sid\":\"testdoc\"}],\"Version\":\"2012-10-17\"}", 448 | "tags": null, 449 | "tags_all": { 450 | "Source": "demo-aws-test", 451 | "SourceVersion": "27NwiYBI3" 452 | } 453 | }, 454 | "after_unknown": { 455 | "arn": true, 456 | "id": true, 457 | "name_prefix": true, 458 | "policy_id": true, 459 | "tags_all": {} 460 | }, 461 | "before_sensitive": { 462 | "tags": {}, 463 | "tags_all": {} 464 | }, 465 | "after_sensitive": { 466 | "tags_all": {} 467 | } 468 | }, 469 | "action_reason": "replace_because_tainted" 470 | }, 471 | { 472 | "address": "aws_iam_policy.unchanged", 473 | "mode": "managed", 474 | "type": "aws_iam_policy", 475 | "name": "unchanged", 476 | "provider_name": "registry.terraform.io/hashicorp/aws", 477 | "change": { 478 | "actions": [ 479 | "no-op" 480 | ], 481 | "before": { 482 | "arn": "arn:aws:iam::123456789012:policy/test-policy-unchanged", 483 | "description": "", 484 | "id": "arn:aws:iam::123456789012:policy/test-policy-unchanged", 485 | "name": "test-policy-unchanged", 486 | "name_prefix": "", 487 | "path": "/", 488 | "policy": "{\"Statement\":[{\"Action\":\"s3:Get*\",\"Effect\":\"Allow\",\"Resource\":\"*\",\"Sid\":\"testdoc\"}],\"Version\":\"2012-10-17\"}", 489 | "policy_id": "ANPAR2NUVQKSU2IBZAFHO", 490 | "tags": {}, 491 | "tags_all": { 492 | "Source": "demo-aws-test", 493 | "SourceVersion": "27NwiYBI3" 494 | } 495 | }, 496 | "after": { 497 | "arn": "arn:aws:iam::123456789012:policy/test-policy-unchanged", 498 | "description": "", 499 | "id": "arn:aws:iam::123456789012:policy/test-policy-unchanged", 500 | "name": "test-policy-unchanged", 501 | "name_prefix": "", 502 | "path": "/", 503 | "policy": "{\"Statement\":[{\"Action\":\"s3:Get*\",\"Effect\":\"Allow\",\"Resource\":\"*\",\"Sid\":\"testdoc\"}],\"Version\":\"2012-10-17\"}", 504 | "policy_id": "ANPAR2NUVQKSU2IBZAFHO", 505 | "tags": {}, 506 | "tags_all": { 507 | "Source": "demo-aws-test", 508 | "SourceVersion": "27NwiYBI3" 509 | } 510 | }, 511 | "after_unknown": {}, 512 | "before_sensitive": { 513 | "tags": {}, 514 | "tags_all": {} 515 | }, 516 | "after_sensitive": { 517 | "tags": {}, 518 | "tags_all": {} 519 | } 520 | } 521 | }, 522 | { 523 | "address": "random_string.version", 524 | "mode": "managed", 525 | "type": "random_string", 526 | "name": "version", 527 | "provider_name": "registry.terraform.io/hashicorp/random", 528 | "change": { 529 | "actions": [ 530 | "no-op" 531 | ], 532 | "before": { 533 | "id": "27NwiYBI", 534 | "keepers": null, 535 | "length": 8, 536 | "lower": true, 537 | "min_lower": 0, 538 | "min_numeric": 0, 539 | "min_special": 0, 540 | "min_upper": 0, 541 | "number": true, 542 | "numeric": true, 543 | "override_special": null, 544 | "result": "27NwiYBI", 545 | "special": false, 546 | "upper": true 547 | }, 548 | "after": { 549 | "id": "27NwiYBI", 550 | "keepers": null, 551 | "length": 8, 552 | "lower": true, 553 | "min_lower": 0, 554 | "min_numeric": 0, 555 | "min_special": 0, 556 | "min_upper": 0, 557 | "number": true, 558 | "numeric": true, 559 | "override_special": null, 560 | "result": "27NwiYBI", 561 | "special": false, 562 | "upper": true 563 | }, 564 | "after_unknown": {}, 565 | "before_sensitive": {}, 566 | "after_sensitive": {} 567 | } 568 | } 569 | ], 570 | "prior_state": { 571 | "format_version": "1.0", 572 | "terraform_version": "1.2.9", 573 | "values": { 574 | "root_module": { 575 | "resources": [ 576 | { 577 | "address": "aws_iam_policy.changed", 578 | "mode": "managed", 579 | "type": "aws_iam_policy", 580 | "name": "changed", 581 | "provider_name": "registry.terraform.io/hashicorp/aws", 582 | "schema_version": 0, 583 | "values": { 584 | "arn": "arn:aws:iam::123456789012:policy/test-policy-change", 585 | "description": "", 586 | "id": "arn:aws:iam::123456789012:policy/test-policy-change", 587 | "name": "test-policy-change", 588 | "name_prefix": "", 589 | "path": "/", 590 | "policy": "{\"Statement\":[{\"Action\":\"s3:Get*\",\"Effect\":\"Allow\",\"Resource\":\"*\",\"Sid\":\"testdoc\"}],\"Version\":\"2012-10-17\"}", 591 | "policy_id": "ANPAR2DEMO", 592 | "tags": {}, 593 | "tags_all": { 594 | "Source": "demo-aws-test", 595 | "SourceVersion": "27NwiYBI3" 596 | } 597 | }, 598 | "sensitive_values": { 599 | "tags": {}, 600 | "tags_all": {} 601 | }, 602 | "depends_on": [ 603 | "data.aws_iam_policy_document.change", 604 | "random_string.version" 605 | ] 606 | }, 607 | { 608 | "address": "aws_iam_policy.destroyed", 609 | "mode": "managed", 610 | "type": "aws_iam_policy", 611 | "name": "destroyed", 612 | "provider_name": "registry.terraform.io/hashicorp/aws", 613 | "schema_version": 0, 614 | "values": { 615 | "arn": "arn:aws:iam::123456789012:policy/test-policy-destroyed", 616 | "description": "", 617 | "id": "arn:aws:iam::123456789012:policy/test-policy-destroyed", 618 | "name": "test-policy-destroyed", 619 | "name_prefix": "", 620 | "path": "/", 621 | "policy": "{\"Statement\":[{\"Action\":\"s3:Get*\",\"Effect\":\"Allow\",\"Resource\":\"*\",\"Sid\":\"testdoc\"}],\"Version\":\"2012-10-17\"}", 622 | "policy_id": "DEMOLIIFZ3", 623 | "tags": {}, 624 | "tags_all": { 625 | "Source": "demo-aws-test", 626 | "SourceVersion": "27NwiYBI3" 627 | } 628 | }, 629 | "sensitive_values": { 630 | "tags": {}, 631 | "tags_all": {} 632 | }, 633 | "depends_on": [ 634 | "data.aws_iam_policy_document.unchanged", 635 | "random_string.version" 636 | ] 637 | }, 638 | { 639 | "address": "aws_iam_policy.tag_and_change", 640 | "mode": "managed", 641 | "type": "aws_iam_policy", 642 | "name": "tag_and_change", 643 | "provider_name": "registry.terraform.io/hashicorp/aws", 644 | "schema_version": 0, 645 | "values": { 646 | "arn": "arn:aws:iam::123456789012:policy/test-policy-tag-and-change", 647 | "description": "", 648 | "id": "arn:aws:iam::123456789012:policy/test-policy-tag-and-change", 649 | "name": "test-policy-tag-and-change", 650 | "name_prefix": "", 651 | "path": "/", 652 | "policy": "{\"Statement\":[{\"Action\":\"s3:Get*\",\"Effect\":\"Allow\",\"Resource\":\"*\",\"Sid\":\"testdoc\"}],\"Version\":\"2012-10-17\"}", 653 | "policy_id": "ANPAR2NUVQKSU5XSSXLPG", 654 | "tags": { 655 | "SourceVersion": "27NwiYBI6" 656 | }, 657 | "tags_all": { 658 | "Source": "demo-aws-test", 659 | "SourceVersion": "27NwiYBI6" 660 | } 661 | }, 662 | "sensitive_values": { 663 | "tags": {}, 664 | "tags_all": {} 665 | }, 666 | "depends_on": [ 667 | "data.aws_iam_policy_document.change", 668 | "random_string.version" 669 | ] 670 | }, 671 | { 672 | "address": "aws_iam_policy.tag_only", 673 | "mode": "managed", 674 | "type": "aws_iam_policy", 675 | "name": "tag_only", 676 | "provider_name": "registry.terraform.io/hashicorp/aws", 677 | "schema_version": 0, 678 | "values": { 679 | "arn": "arn:aws:iam::123456789012:policy/test-policy-tag-only", 680 | "description": "", 681 | "id": "arn:aws:iam::123456789012:policy/test-policy-tag-only", 682 | "name": "test-policy-tag-only", 683 | "name_prefix": "", 684 | "path": "/", 685 | "policy": "{\"Statement\":[{\"Action\":\"s3:Get*\",\"Effect\":\"Allow\",\"Resource\":\"*\",\"Sid\":\"testdoc\"}],\"Version\":\"2012-10-17\"}", 686 | "policy_id": "ANPAR2NUVQKSYF3ZBGWIM", 687 | "tags": {}, 688 | "tags_all": { 689 | "Source": "demo-aws-test", 690 | "SourceVersion": "27NwiYBI3" 691 | } 692 | }, 693 | "sensitive_values": { 694 | "tags": {}, 695 | "tags_all": {} 696 | }, 697 | "depends_on": [ 698 | "data.aws_iam_policy_document.unchanged", 699 | "random_string.version" 700 | ] 701 | }, 702 | { 703 | "address": "aws_iam_policy.tainted", 704 | "mode": "managed", 705 | "type": "aws_iam_policy", 706 | "name": "tainted", 707 | "provider_name": "registry.terraform.io/hashicorp/aws", 708 | "schema_version": 0, 709 | "values": { 710 | "arn": "arn:aws:iam::123456789012:policy/test-policy-tainted", 711 | "description": "", 712 | "id": "arn:aws:iam::123456789012:policy/test-policy-tainted", 713 | "name": "test-policy-tainted", 714 | "name_prefix": "", 715 | "path": "/", 716 | "policy": "{\"Statement\":[{\"Action\":\"s3:Get*\",\"Effect\":\"Allow\",\"Resource\":\"*\",\"Sid\":\"testdoc\"}],\"Version\":\"2012-10-17\"}", 717 | "policy_id": "ANPAR2NUVQKSV46NWXCIW", 718 | "tags": {}, 719 | "tags_all": { 720 | "Source": "demo-aws-test", 721 | "SourceVersion": "27NwiYBI3" 722 | } 723 | }, 724 | "sensitive_values": { 725 | "tags": {}, 726 | "tags_all": {} 727 | }, 728 | "depends_on": [ 729 | "data.aws_iam_policy_document.unchanged", 730 | "random_string.version" 731 | ], 732 | "tainted": true 733 | }, 734 | { 735 | "address": "aws_iam_policy.unchanged", 736 | "mode": "managed", 737 | "type": "aws_iam_policy", 738 | "name": "unchanged", 739 | "provider_name": "registry.terraform.io/hashicorp/aws", 740 | "schema_version": 0, 741 | "values": { 742 | "arn": "arn:aws:iam::123456789012:policy/test-policy-unchanged", 743 | "description": "", 744 | "id": "arn:aws:iam::123456789012:policy/test-policy-unchanged", 745 | "name": "test-policy-unchanged", 746 | "name_prefix": "", 747 | "path": "/", 748 | "policy": "{\"Statement\":[{\"Action\":\"s3:Get*\",\"Effect\":\"Allow\",\"Resource\":\"*\",\"Sid\":\"testdoc\"}],\"Version\":\"2012-10-17\"}", 749 | "policy_id": "ANPAR2NUVQKSU2IBZAFHO", 750 | "tags": {}, 751 | "tags_all": { 752 | "Source": "demo-aws-test", 753 | "SourceVersion": "27NwiYBI3" 754 | } 755 | }, 756 | "sensitive_values": { 757 | "tags": {}, 758 | "tags_all": {} 759 | }, 760 | "depends_on": [ 761 | "data.aws_iam_policy_document.unchanged", 762 | "random_string.version" 763 | ] 764 | }, 765 | { 766 | "address": "data.aws_iam_policy_document.change", 767 | "mode": "data", 768 | "type": "aws_iam_policy_document", 769 | "name": "change", 770 | "provider_name": "registry.terraform.io/hashicorp/aws", 771 | "schema_version": 0, 772 | "values": { 773 | "id": "1388270941", 774 | "json": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"testdoc\",\n \"Effect\": \"Allow\",\n \"Action\": \"s3:*\",\n \"Resource\": \"*\"\n }\n ]\n}", 775 | "override_json": null, 776 | "override_policy_documents": null, 777 | "policy_id": null, 778 | "source_json": null, 779 | "source_policy_documents": null, 780 | "statement": [ 781 | { 782 | "actions": [ 783 | "s3:*" 784 | ], 785 | "condition": [], 786 | "effect": "Allow", 787 | "not_actions": [], 788 | "not_principals": [], 789 | "not_resources": [], 790 | "principals": [], 791 | "resources": [ 792 | "*" 793 | ], 794 | "sid": "testdoc" 795 | } 796 | ], 797 | "version": "2012-10-17" 798 | }, 799 | "sensitive_values": { 800 | "statement": [ 801 | { 802 | "actions": [ 803 | false 804 | ], 805 | "condition": [], 806 | "not_actions": [], 807 | "not_principals": [], 808 | "not_resources": [], 809 | "principals": [], 810 | "resources": [ 811 | false 812 | ] 813 | } 814 | ] 815 | } 816 | }, 817 | { 818 | "address": "data.aws_iam_policy_document.unchanged", 819 | "mode": "data", 820 | "type": "aws_iam_policy_document", 821 | "name": "unchanged", 822 | "provider_name": "registry.terraform.io/hashicorp/aws", 823 | "schema_version": 0, 824 | "values": { 825 | "id": "1270208521", 826 | "json": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"testdoc\",\n \"Effect\": \"Allow\",\n \"Action\": \"s3:Get*\",\n \"Resource\": \"*\"\n }\n ]\n}", 827 | "override_json": null, 828 | "override_policy_documents": null, 829 | "policy_id": null, 830 | "source_json": null, 831 | "source_policy_documents": null, 832 | "statement": [ 833 | { 834 | "actions": [ 835 | "s3:Get*" 836 | ], 837 | "condition": [], 838 | "effect": "Allow", 839 | "not_actions": [], 840 | "not_principals": [], 841 | "not_resources": [], 842 | "principals": [], 843 | "resources": [ 844 | "*" 845 | ], 846 | "sid": "testdoc" 847 | } 848 | ], 849 | "version": "2012-10-17" 850 | }, 851 | "sensitive_values": { 852 | "statement": [ 853 | { 854 | "actions": [ 855 | false 856 | ], 857 | "condition": [], 858 | "not_actions": [], 859 | "not_principals": [], 860 | "not_resources": [], 861 | "principals": [], 862 | "resources": [ 863 | false 864 | ] 865 | } 866 | ] 867 | } 868 | }, 869 | { 870 | "address": "random_string.version", 871 | "mode": "managed", 872 | "type": "random_string", 873 | "name": "version", 874 | "provider_name": "registry.terraform.io/hashicorp/random", 875 | "schema_version": 2, 876 | "values": { 877 | "id": "27NwiYBI", 878 | "keepers": null, 879 | "length": 8, 880 | "lower": true, 881 | "min_lower": 0, 882 | "min_numeric": 0, 883 | "min_special": 0, 884 | "min_upper": 0, 885 | "number": true, 886 | "numeric": true, 887 | "override_special": null, 888 | "result": "27NwiYBI", 889 | "special": false, 890 | "upper": true 891 | }, 892 | "sensitive_values": {} 893 | } 894 | ] 895 | } 896 | } 897 | }, 898 | "configuration": { 899 | "provider_config": { 900 | "aws": { 901 | "name": "aws", 902 | "full_name": "registry.terraform.io/hashicorp/aws", 903 | "version_constraint": "~\u003e 4.0", 904 | "expressions": { 905 | "default_tags": [ 906 | { 907 | "tags": { 908 | "references": [ 909 | "random_string.version.result", 910 | "random_string.version" 911 | ] 912 | } 913 | } 914 | ], 915 | "region": { 916 | "constant_value": "us-west-2" 917 | } 918 | } 919 | }, 920 | "random": { 921 | "name": "random", 922 | "full_name": "registry.terraform.io/hashicorp/random" 923 | } 924 | }, 925 | "root_module": { 926 | "resources": [ 927 | { 928 | "address": "aws_iam_policy.changed", 929 | "mode": "managed", 930 | "type": "aws_iam_policy", 931 | "name": "changed", 932 | "provider_config_key": "aws", 933 | "expressions": { 934 | "name": { 935 | "constant_value": "test-policy-change" 936 | }, 937 | "policy": { 938 | "references": [ 939 | "data.aws_iam_policy_document.change.json", 940 | "data.aws_iam_policy_document.change" 941 | ] 942 | } 943 | }, 944 | "schema_version": 0 945 | }, 946 | { 947 | "address": "aws_iam_policy.created", 948 | "mode": "managed", 949 | "type": "aws_iam_policy", 950 | "name": "created", 951 | "provider_config_key": "aws", 952 | "expressions": { 953 | "name": { 954 | "constant_value": "test-policy-created" 955 | }, 956 | "policy": { 957 | "references": [ 958 | "data.aws_iam_policy_document.unchanged.json", 959 | "data.aws_iam_policy_document.unchanged" 960 | ] 961 | } 962 | }, 963 | "schema_version": 0 964 | }, 965 | { 966 | "address": "aws_iam_policy.tag_and_change", 967 | "mode": "managed", 968 | "type": "aws_iam_policy", 969 | "name": "tag_and_change", 970 | "provider_config_key": "aws", 971 | "expressions": { 972 | "name": { 973 | "constant_value": "test-policy-tag-and-change" 974 | }, 975 | "policy": { 976 | "references": [ 977 | "data.aws_iam_policy_document.change.json", 978 | "data.aws_iam_policy_document.change" 979 | ] 980 | } 981 | }, 982 | "schema_version": 0 983 | }, 984 | { 985 | "address": "aws_iam_policy.tag_only", 986 | "mode": "managed", 987 | "type": "aws_iam_policy", 988 | "name": "tag_only", 989 | "provider_config_key": "aws", 990 | "expressions": { 991 | "name": { 992 | "constant_value": "test-policy-tag-only" 993 | }, 994 | "policy": { 995 | "references": [ 996 | "data.aws_iam_policy_document.unchanged.json", 997 | "data.aws_iam_policy_document.unchanged" 998 | ] 999 | }, 1000 | "tags": { 1001 | "references": [ 1002 | "random_string.version.result", 1003 | "random_string.version" 1004 | ] 1005 | } 1006 | }, 1007 | "schema_version": 0 1008 | }, 1009 | { 1010 | "address": "aws_iam_policy.tainted", 1011 | "mode": "managed", 1012 | "type": "aws_iam_policy", 1013 | "name": "tainted", 1014 | "provider_config_key": "aws", 1015 | "expressions": { 1016 | "name": { 1017 | "constant_value": "test-policy-tainted" 1018 | }, 1019 | "policy": { 1020 | "references": [ 1021 | "data.aws_iam_policy_document.unchanged.json", 1022 | "data.aws_iam_policy_document.unchanged" 1023 | ] 1024 | } 1025 | }, 1026 | "schema_version": 0 1027 | }, 1028 | { 1029 | "address": "aws_iam_policy.unchanged", 1030 | "mode": "managed", 1031 | "type": "aws_iam_policy", 1032 | "name": "unchanged", 1033 | "provider_config_key": "aws", 1034 | "expressions": { 1035 | "name": { 1036 | "constant_value": "test-policy-unchanged" 1037 | }, 1038 | "policy": { 1039 | "references": [ 1040 | "data.aws_iam_policy_document.unchanged.json", 1041 | "data.aws_iam_policy_document.unchanged" 1042 | ] 1043 | } 1044 | }, 1045 | "schema_version": 0 1046 | }, 1047 | { 1048 | "address": "random_string.version", 1049 | "mode": "managed", 1050 | "type": "random_string", 1051 | "name": "version", 1052 | "provider_config_key": "random", 1053 | "expressions": { 1054 | "length": { 1055 | "constant_value": 8 1056 | }, 1057 | "special": { 1058 | "constant_value": false 1059 | } 1060 | }, 1061 | "schema_version": 2 1062 | }, 1063 | { 1064 | "address": "data.aws_iam_policy_document.change", 1065 | "mode": "data", 1066 | "type": "aws_iam_policy_document", 1067 | "name": "change", 1068 | "provider_config_key": "aws", 1069 | "expressions": { 1070 | "statement": [ 1071 | { 1072 | "actions": { 1073 | "constant_value": [ 1074 | "s3:*" 1075 | ] 1076 | }, 1077 | "effect": { 1078 | "constant_value": "Allow" 1079 | }, 1080 | "resources": { 1081 | "constant_value": [ 1082 | "*" 1083 | ] 1084 | }, 1085 | "sid": { 1086 | "constant_value": "testdoc" 1087 | } 1088 | } 1089 | ] 1090 | }, 1091 | "schema_version": 0 1092 | }, 1093 | { 1094 | "address": "data.aws_iam_policy_document.unchanged", 1095 | "mode": "data", 1096 | "type": "aws_iam_policy_document", 1097 | "name": "unchanged", 1098 | "provider_config_key": "aws", 1099 | "expressions": { 1100 | "statement": [ 1101 | { 1102 | "actions": { 1103 | "constant_value": [ 1104 | "s3:Get*" 1105 | ] 1106 | }, 1107 | "effect": { 1108 | "constant_value": "Allow" 1109 | }, 1110 | "resources": { 1111 | "constant_value": [ 1112 | "*" 1113 | ] 1114 | }, 1115 | "sid": { 1116 | "constant_value": "testdoc" 1117 | } 1118 | } 1119 | ] 1120 | }, 1121 | "schema_version": 0 1122 | } 1123 | ] 1124 | } 1125 | }, 1126 | "relevant_attributes": [ 1127 | { 1128 | "resource": "data.aws_iam_policy_document.change", 1129 | "attribute": [ 1130 | "json" 1131 | ] 1132 | }, 1133 | { 1134 | "resource": "data.aws_iam_policy_document.unchanged", 1135 | "attribute": [ 1136 | "json" 1137 | ] 1138 | }, 1139 | { 1140 | "resource": "random_string.version", 1141 | "attribute": [ 1142 | "result" 1143 | ] 1144 | } 1145 | ] 1146 | } 1147 | --------------------------------------------------------------------------------