├── .editorconfig ├── .github ├── actionlint.yaml ├── dependabot.yml ├── publish-techdocs-testdata │ ├── docs │ │ └── README.md │ └── mkdocs.yml ├── renovate-config.json5 ├── workflows │ ├── README.md │ ├── build-trigger-argo-workflow.yaml │ ├── check-catalog-info.yaml │ ├── check-drone-signature.md │ ├── check-drone-signature.yaml │ ├── check-for-non-releasable-actions.yaml │ ├── codeql.yml │ ├── dependency-review.yml │ ├── lint-pr-title.yml │ ├── lint-shared-workflows.yaml │ ├── publish-techdocs.md │ ├── publish-techdocs.yaml │ ├── release.yml │ ├── renovate.yml │ ├── reusable-zizmor.md │ ├── reusable-zizmor.yml │ ├── scorecards.yml │ ├── self-zizmor.yml │ ├── test-find-pr-for-commit.yml │ ├── test-get-vault-secrets.yaml │ ├── test-lint-pr-title.yml │ ├── test-login-to-gar.yaml │ ├── test-publish-techdocs.yml │ ├── test-remove-checkout-credentials.yaml │ ├── test-setup-argo.yml │ ├── test-setup-jrsonnet.yml │ ├── test-techdocs-rewrite-relative-links.yaml │ └── test-zizmor-offline.yml └── zizmor.yml ├── .gitignore ├── .markdownlint.json ├── .pre-commit-config.yaml ├── .prettierignore ├── .prettierrc.yaml ├── .release-please-manifest.json ├── CODEOWNERS ├── CONTRIBUTING.md ├── LICENSE ├── Makefile ├── README.md ├── actions ├── argo-lint │ ├── CHANGELOG.md │ ├── README.md │ └── action.yaml ├── aws-auth │ ├── CHANGELOG.md │ ├── README.md │ ├── action.yaml │ └── resolve-aws-region.sh ├── build-push-to-dockerhub │ ├── CHANGELOG.md │ ├── README.md │ └── action.yaml ├── dependabot-auto-triage │ ├── .bun-version │ ├── .gitignore │ ├── CHANGELOG.md │ ├── README.md │ ├── action.yml │ ├── bun.lock │ ├── eslint.config.mjs │ ├── package.json │ ├── src │ │ ├── index.test.ts │ │ └── index.ts │ └── tsconfig.json ├── dockerhub-login │ ├── CHANGELOG.md │ ├── README.md │ └── action.yaml ├── find-pr-for-commit │ ├── CHANGELOG.md │ ├── README.md │ └── action.yaml ├── generate-openapi-clients │ ├── CHANGELOG.md │ ├── README.md │ ├── action.yaml │ ├── generate.sh │ └── templates │ │ └── go │ │ └── model_simple.mustache ├── get-latest-workflow-artifact │ ├── .bun-version │ ├── .gitignore │ ├── CHANGELOG.md │ ├── README.md │ ├── action.yml │ ├── bun.lock │ ├── package.json │ └── src │ │ └── main.ts ├── get-vault-secrets │ ├── CHANGELOG.md │ ├── README.md │ ├── action.yaml │ ├── translate-secrets.bash │ └── translate-secrets.bats ├── lint-pr-title │ ├── .bun-version │ ├── .gitignore │ ├── CHANGELOG.md │ ├── Dockerfile │ ├── README.md │ ├── action.yml │ ├── bun.lock │ ├── commitlint.config.js │ ├── eslint.config.mjs │ ├── package.json │ ├── src │ │ ├── index.test.ts │ │ ├── index.ts │ │ ├── main.test.ts │ │ ├── main.ts │ │ ├── tempfile.test.ts │ │ ├── tempfile.ts │ │ └── testUtils │ │ │ ├── compareCommitsWithBaseheadresponses.ts │ │ │ ├── context.ts │ │ │ ├── index.ts │ │ │ ├── mergeGroupContext.ts │ │ │ ├── pullRequestContext.ts │ │ │ └── tsMatchers.ts │ └── tsconfig.json ├── login-to-gar │ ├── CHANGELOG.md │ ├── README.md │ └── action.yaml ├── login-to-gcs │ ├── CHANGELOG.md │ ├── README.md │ └── action.yaml ├── push-to-gar-docker │ ├── CHANGELOG.md │ ├── README.md │ └── action.yaml ├── push-to-gcs │ ├── CHANGELOG.md │ ├── README.md │ └── action.yaml ├── remove-checkout-credentials │ ├── CHANGELOG.md │ ├── README.md │ └── action.yaml ├── send-slack-message │ ├── CHANGELOG.md │ ├── README.md │ └── action.yaml ├── setup-argo │ ├── CHANGELOG.md │ ├── README.md │ └── action.yaml ├── setup-conftest │ ├── CHANGELOG.md │ ├── README.md │ └── action.yaml ├── setup-jrsonnet │ ├── CHANGELOG.md │ ├── README.md │ └── action.yaml ├── techdocs-rewrite-relative-links │ ├── CHANGELOG.md │ ├── README.md │ ├── action.yaml │ ├── go.mod │ ├── go.sum │ ├── main.go │ └── main_test.go ├── trigger-argo-workflow │ ├── CHANGELOG.md │ ├── README.md │ ├── action.yaml │ ├── cmd │ │ └── trigger-argo-workflow │ │ │ ├── argo.go │ │ │ ├── argo_test.go │ │ │ ├── argoflags.go │ │ │ ├── argoflags_test.go │ │ │ └── main.go │ ├── go.mod │ └── go.sum └── validate-policy-bot-config │ ├── CHANGELOG.md │ ├── README.md │ └── action.yml ├── catalog-info.yaml ├── release-please-config.json └── scripts └── generate-catalog-info ├── go.mod ├── go.sum └── main.go /.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | charset = utf-8 3 | trim_trailing_whitespace = true 4 | insert_final_newline = true 5 | 6 | [*.yaml] 7 | quote_type = double 8 | indent_style = space 9 | indent_size = 2 10 | -------------------------------------------------------------------------------- /.github/actionlint.yaml: -------------------------------------------------------------------------------- 1 | self-hosted-runner: 2 | # Labels of self-hosted runner in array of strings. 3 | labels: 4 | - ubuntu-amd64* 5 | - ubuntu-x64* 6 | - ubuntu-arm64* 7 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # Set update schedule for GitHub Actions 2 | 3 | version: 2 4 | updates: 5 | - package-ecosystem: "gomod" 6 | directory: "/actions/trigger-argo-workflow" 7 | schedule: 8 | interval: "weekly" 9 | groups: 10 | go: 11 | applies-to: "version-updates" 12 | patterns: 13 | - "*" 14 | 15 | - package-ecosystem: "gomod" 16 | directory: "/actions/techdocs-rewrite-relative-links" 17 | schedule: 18 | interval: "weekly" 19 | groups: 20 | go: 21 | applies-to: "version-updates" 22 | patterns: 23 | - "*" 24 | -------------------------------------------------------------------------------- /.github/publish-techdocs-testdata/docs/README.md: -------------------------------------------------------------------------------- 1 | # Test docs 2 | 3 | Lovely stuff. 4 | -------------------------------------------------------------------------------- /.github/publish-techdocs-testdata/mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: "test-docs" 2 | 3 | nav: 4 | - Home: README.md 5 | 6 | plugins: 7 | - techdocs-core 8 | -------------------------------------------------------------------------------- /.github/renovate-config.json5: -------------------------------------------------------------------------------- 1 | { 2 | $schema: "https://docs.renovatebot.com/renovate-schema.json", 3 | branchPrefix: "grafanarenovatebot/", 4 | customManagers: [ 5 | { 6 | customType: "regex", 7 | fileMatch: [ 8 | "(?:^|/)\\.github/(?:workflows|actions)/.+\\.ya?ml$", 9 | "(?:^|/)action\\.ya?ml$", 10 | ], 11 | matchStrings: [ 12 | "# renovate: datasource=(?[a-z-.]+?) depName=(?[^\\s]+?)(?: (?:lookupName|packageName)=(?[^\\s]+?))?(?: versioning=(?[^\\s]+?))?(?: extractVersion=(?[^\\s]+?))?\\s+[A-Za-z0-9_-]+[_-](?:VERSION|version)\\s*[:=]\\s*[\"']?(?[^\"'@\\n]+)(?:@(?sha256:[a-f0-9]+))?[\"']?", 13 | ], 14 | }, 15 | ], 16 | dependencyDashboard: false, 17 | enabledManagers: [ 18 | "bun", 19 | "bun-version", 20 | "custom.regex", 21 | "github-actions", 22 | "npm", 23 | ], 24 | forkProcessing: "enabled", 25 | globalExtends: [":pinDependencies", "config:best-practices"], 26 | onboarding: false, 27 | osvVulnerabilityAlerts: true, 28 | packageRules: [ 29 | { 30 | labels: ["update-major"], 31 | matchUpdateTypes: ["major"], 32 | }, 33 | { 34 | labels: ["update-minor"], 35 | matchUpdateTypes: ["minor"], 36 | }, 37 | { 38 | automerge: true, 39 | labels: ["automerge-patch"], 40 | matchUpdateTypes: ["patch"], 41 | }, 42 | { 43 | labels: ["update-digest"], 44 | matchUpdateTypes: ["digest"], 45 | }, 46 | { 47 | // Run the custom matcher on early Monday mornings (UTC) 48 | schedule: "* 0-4 * * 1", 49 | matchPackageNames: ["ghcr.io/renovatebot/renovate"], 50 | }, 51 | ], 52 | platformCommit: "enabled", 53 | rebaseWhen: "behind-base-branch", 54 | requireConfig: "optional", 55 | vulnerabilityAlerts: { 56 | automerge: true, 57 | enabled: true, 58 | labels: ["automerge-security-update"], 59 | }, 60 | } 61 | -------------------------------------------------------------------------------- /.github/workflows/README.md: -------------------------------------------------------------------------------- 1 | # GitHub workflows 2 | 3 | ## Reusable workflows 4 | 5 | This folder contains some workflows that can be re-used from other repositories: 6 | 7 | - [`publish-techdocs`](./publish-techdocs.md): Publish your project's 8 | documentation to EngHub 9 | 10 | - [`reusable-zizmor`](./reusable-zizmor.md): Run [zizmor] static analysis on 11 | your GitHub Actions workflow files. 12 | 13 | [zizmor]: https://woodruffw.github.io/zizmor/ 14 | -------------------------------------------------------------------------------- /.github/workflows/build-trigger-argo-workflow.yaml: -------------------------------------------------------------------------------- 1 | name: Build, lint and test `trigger-argo-workflow` 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths: 8 | - "actions/trigger-argo-workflow/**" 9 | pull_request: 10 | paths: 11 | - "actions/trigger-argo-workflow/**" 12 | types: 13 | - edited 14 | - opened 15 | - ready_for_review 16 | - synchronize 17 | merge_group: 18 | 19 | permissions: 20 | contents: read 21 | 22 | jobs: 23 | lint-test-build: 24 | runs-on: ubuntu-latest 25 | defaults: 26 | run: 27 | working-directory: actions/trigger-argo-workflow 28 | permissions: 29 | contents: read 30 | 31 | steps: 32 | - name: Harden the runner (Audit all outbound calls) 33 | uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 34 | with: 35 | egress-policy: audit 36 | 37 | - name: Checkout code 38 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 39 | with: 40 | persist-credentials: false 41 | 42 | - uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0 43 | with: 44 | check-latest: true 45 | cache-dependency-path: | 46 | actions/trigger-argo-workflow/go.sum 47 | go-version-file: "actions/trigger-argo-workflow/go.mod" 48 | 49 | - name: golangci-lint 50 | uses: golangci/golangci-lint-action@1481404843c368bc19ca9406f87d6e0fc97bdcfd # v7.0.0 51 | with: 52 | version: latest 53 | working-directory: actions/trigger-argo-workflow 54 | 55 | - name: Run tests 56 | run: go test -v ./... 57 | 58 | - name: Build 59 | run: go build -o trigger-argo-workflow ./... 60 | -------------------------------------------------------------------------------- /.github/workflows/check-catalog-info.yaml: -------------------------------------------------------------------------------- 1 | name: Check catalog-info.yaml for drift 2 | on: 3 | pull_request: {} 4 | 5 | permissions: 6 | contents: read 7 | 8 | jobs: 9 | check-catalog-info-drift: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Harden the runner (Audit all outbound calls) 13 | uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 14 | with: 15 | egress-policy: audit 16 | 17 | - name: Checkout 18 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 19 | with: 20 | persist-credentials: false 21 | 22 | - name: Setup Go 23 | uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0 24 | 25 | - name: Regenerate catalog-info.yaml 26 | run: | 27 | make catalog-info.yaml 28 | 29 | - name: Check for drift 30 | run: | 31 | if ! git diff --staged --exit-code; then 32 | echo "catalog-info.yaml is not up-to-date, please run \`make catalog-info.yaml\` to update this file." 33 | exit 1 34 | fi 35 | -------------------------------------------------------------------------------- /.github/workflows/check-drone-signature.md: -------------------------------------------------------------------------------- 1 | # Check Drone Signature 2 | 3 | ## Overview 4 | 5 | This document describes the intention and usage of the `check-drone-signature` GitHub Actions workflow. 6 | You can find [the `check-drone-signature` workflow file here][wf-file]. 7 | 8 | This reusable workflow checks [the signature of a Drone CI file][drone-sig] against our Drone server and fails if the signature is invalid. 9 | The check can help prevent against merging incorrectly signed files, which often occurs when the Drone CI config is modified without re-signing the file. 10 | When a signature is invalid, Drone CI builds require approval from a user with write or administrative access to proceed. 11 | Only those users with write or administrative access to the repository can create the signature using `drone sign $owner/$repo --save`. 12 | 13 | This check is particularly useful in our public OSS repositories, as those require a signed config file. 14 | Beyond public repos, any Drone repositories that are `Protected` require a signed config file. 15 | 16 | [wf-file]: ./check-drone-signature.yaml 17 | [drone-sig]: https://docs.drone.io/signature/ 18 | 19 | ## Usage 20 | 21 | The following is an example of how to use the `check-drone-signature` workflow in your repository: 22 | 23 | ```yaml 24 | name: Check Drone CI Signature 25 | 26 | on: 27 | push: 28 | branches: 29 | - "main" 30 | paths: 31 | - ".drone.yml" 32 | pull_request: 33 | paths: 34 | - ".drone.yml" 35 | 36 | permissions: 37 | id-token: write 38 | contents: read 39 | issues: write 40 | 41 | jobs: 42 | drone-signature-check: 43 | uses: grafana/shared-workflows/.github/workflows/check-drone-signature.yaml@main 44 | with: 45 | drone_config_path: .drone.yml 46 | ``` 47 | 48 | This workflow file expects the following: 49 | 50 | - `main` is the name of your primary branch 51 | - `.drone.yml` is the filename for your Drone CI configuration file and it's located at the root of your repository 52 | 53 | For Grafanistas, you can use [this software template in EngHub][enghub-tmpl] to easily configure and add the workflow file to your repository. 54 | 55 | [enghub-tmpl]: https://enghub.grafana-ops.net/create/templates/default/add-drone-signature-check-workflow 56 | 57 | ### Forks 58 | 59 | Because forks do not have access to the secrets required to check the signature, the workflow will not run on pull requests from forks. 60 | A message will be posted on the pull request indicating that the signature check was skipped. 61 | 62 | ## Inputs 63 | 64 | | Name | Description | Type | 65 | | ------------------- | --------------------------------------- | ------ | 66 | | `drone_config_path` | Path to the Drone CI configuration file | string | 67 | | `drone_server` | Drone CI server URL | string | 68 | -------------------------------------------------------------------------------- /.github/workflows/check-for-non-releasable-actions.yaml: -------------------------------------------------------------------------------- 1 | name: Check for non-releasable actions 2 | on: 3 | pull_request: 4 | types: 5 | - edited 6 | - opened 7 | - ready_for_review 8 | - synchronize 9 | 10 | push: 11 | branches: 12 | - main 13 | 14 | permissions: 15 | contents: read 16 | 17 | jobs: 18 | check-for-non-releasable-actions: 19 | permissions: 20 | contents: read 21 | id-token: write 22 | runs-on: ubuntu-latest 23 | timeout-minutes: 5 24 | 25 | steps: 26 | - name: Harden the runner (Audit all outbound calls) 27 | uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 28 | with: 29 | egress-policy: audit 30 | 31 | - name: Checkout Code 32 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 33 | with: 34 | persist-credentials: false 35 | sparse-checkout: | 36 | ./actions 37 | ./release-please-config.json 38 | 39 | - name: Check for non-releasable actions 40 | uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7 41 | with: 42 | script: | 43 | const fs = require('fs/promises'); 44 | const releasePleaseConfig = JSON.parse(await fs.readFile('release-please-config.json', 'utf-8')); 45 | 46 | const configuredPackageNames = new Set(Object.keys(releasePleaseConfig.packages)); 47 | const packageNames = new Set(); 48 | 49 | const folders = await fs.readdir('actions', { withFileTypes: true }); 50 | for (const folder of folders) { 51 | if (folder.isDirectory()) { 52 | packageNames.add('actions/' + folder.name); 53 | } 54 | } 55 | 56 | const missingConfigurations = [...packageNames].filter(pkg => !configuredPackageNames.has(pkg)); 57 | 58 | if (missingConfigurations.length > 0) { 59 | console.log('The following actions are missing from the release-please-config.json file and thus won\'t be automatically released:'); 60 | console.log(missingConfigurations.join('\n')); 61 | console.log('Please add them in release-please-config.json!'); 62 | } else { 63 | console.log('All actions are releasable!'); 64 | } 65 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL" 2 | 3 | on: 4 | push: 5 | branches: 6 | - "main" 7 | 8 | pull_request: 9 | branches: 10 | - "main" 11 | types: 12 | - edited 13 | - opened 14 | - ready_for_review 15 | - synchronize 16 | 17 | schedule: 18 | - cron: "21 5 * * 3" 19 | 20 | # To trigger a CodeQL analysis manually 21 | workflow_dispatch: 22 | 23 | permissions: 24 | contents: read 25 | 26 | jobs: 27 | analyze: 28 | name: Analyze (${{ matrix.language }}) 29 | 30 | runs-on: ubuntu-latest-8-cores 31 | 32 | timeout-minutes: 360 33 | 34 | permissions: 35 | security-events: write 36 | 37 | strategy: 38 | fail-fast: false 39 | matrix: 40 | include: 41 | - language: go 42 | build-mode: autobuild 43 | - language: javascript-typescript 44 | build-mode: none 45 | paths-ignore: 46 | - "**/dist/**" 47 | 48 | steps: 49 | - name: Harden the runner (Audit all outbound calls) 50 | uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 51 | with: 52 | egress-policy: audit 53 | 54 | - name: Checkout repository 55 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 56 | with: 57 | persist-credentials: false 58 | 59 | - name: Initialize CodeQL 60 | uses: github/codeql-action/init@28deaeda66b76a05916b6923827895f2b14ab387 # v3.28.16 61 | with: 62 | languages: ${{ matrix.language }} 63 | build-mode: ${{ matrix.build-mode }} 64 | config: | 65 | paths-ignore: ${{ toJSON(matrix.paths-ignore) }} 66 | 67 | - name: Perform CodeQL Analysis 68 | uses: github/codeql-action/analyze@28deaeda66b76a05916b6923827895f2b14ab387 # v3.28.16 69 | with: 70 | category: "/language:${{matrix.language}}" 71 | -------------------------------------------------------------------------------- /.github/workflows/dependency-review.yml: -------------------------------------------------------------------------------- 1 | # Dependency Review Action 2 | # 3 | # This Action will scan dependency manifest files that change as part of a Pull Request, 4 | # surfacing known-vulnerable versions of the packages declared or updated in the PR. 5 | # Once installed, if the workflow run is marked as required, 6 | # PRs introducing known-vulnerable packages will be blocked from merging. 7 | # 8 | # Source repository: https://github.com/actions/dependency-review-action 9 | name: "Dependency Review" 10 | on: 11 | pull_request: 12 | merge_group: 13 | 14 | permissions: 15 | contents: read 16 | 17 | jobs: 18 | dependency-review: 19 | runs-on: ubuntu-latest 20 | steps: 21 | - name: Harden the runner (Audit all outbound calls) 22 | uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 23 | with: 24 | egress-policy: audit 25 | 26 | - name: "Checkout Repository" 27 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 28 | with: 29 | persist-credentials: false 30 | - name: "Dependency Review" 31 | uses: actions/dependency-review-action@67d4f4bd7a9b17a0db54d2a7519187c65e339de8 # v4 32 | -------------------------------------------------------------------------------- /.github/workflows/lint-pr-title.yml: -------------------------------------------------------------------------------- 1 | name: Lint PR title 2 | 3 | on: 4 | pull_request: 5 | types: 6 | - edited 7 | - opened 8 | - ready_for_review 9 | - synchronize 10 | 11 | merge_group: 12 | 13 | permissions: 14 | contents: read 15 | 16 | jobs: 17 | lint-pr-title: 18 | permissions: 19 | contents: read 20 | pull-requests: read 21 | 22 | runs-on: ubuntu-latest 23 | 24 | steps: 25 | - name: Harden the runner (Audit all outbound calls) 26 | uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 27 | with: 28 | egress-policy: audit 29 | 30 | - name: Checkout 31 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 32 | with: 33 | persist-credentials: false 34 | 35 | - id: lint-pr-title 36 | name: Lint PR title 37 | uses: ./actions/lint-pr-title 38 | 39 | # This is an integration test ensuring that we don't regress absolute path 40 | # support 41 | - name: Copy lint-pr-title config to temp dir 42 | run: | 43 | cp actions/lint-pr-title/commitlint.config.js "${{ runner.temp }}/commitlint.config.js" 44 | 45 | - id: lint-pr-title-separate-config 46 | name: Lint PR title with separate config 47 | uses: ./actions/lint-pr-title 48 | with: 49 | config-path: "${{ runner.temp }}/commitlint.config.js" 50 | -------------------------------------------------------------------------------- /.github/workflows/publish-techdocs.md: -------------------------------------------------------------------------------- 1 | # Reusable workflow: Publish techdocs 2 | 3 | This workflow helps you build your project's documentation and publish it to [EngHub](https://enghub.grafana-ops.net). 4 | Please keep in mind that for this you also need to first register your repository with EngHub. 5 | You can find details on this [here](https://enghub.grafana-ops.net/docs/default/component/enghub/user-guides/add-gh-repo/). 6 | 7 | ## Usage example 8 | 9 | ```yaml 10 | name: Publish TechDocs 11 | on: 12 | push: 13 | branches: 14 | - main 15 | paths: 16 | - "docs/**" 17 | - "mkdocs.yml" 18 | - "catalog-info.yaml" 19 | - ".github/workflows/publish-docs.yml" 20 | concurrency: 21 | group: "${{ github.workflow }}-${{ github.ref }}" 22 | cancel-in-progress: true 23 | jobs: 24 | publish-docs: 25 | permissions: 26 | contents: read # to clone the repository to read its docs 27 | id-token: write # to use OIDC to auth with AWS and push the docs to S3 28 | uses: grafana/shared-workflows/.github/workflows/publish-techdocs.yaml@main 29 | with: 30 | namespace: default 31 | kind: component 32 | name: COMPONENT_NAME 33 | ``` 34 | 35 | ## Inputs 36 | 37 | | Name | Type | Description | 38 | | -------------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 39 | | `namespace` | string | The entity's namespace within EngHub (usually `default`) | 40 | | `kind` | string | The kind of the entity in EngHub (usually `component`) | 41 | | `name` | string | The name of the entity in EngHub (usually matches the name of the repository) | 42 | | `default-working-directory` | string | The working directory to use for doc generation. Useful for cases without an mkdocs.yml file at the project root. | 43 | | `rewrite-relative-links` | boolean | Execute [rewrite-relative-links][rewrite-action] step to rewrite relative links in the docs to point to the correct location in the GitHub repository | 44 | | `rewrite-relative-links-dry-run` | boolean | Execute [rewrite-relative-links][rewrite-action] step but only print the diff without modifying the files | 45 | | `publish` | boolean | Enable or disable publishing after building the docs | 46 | | `checkout-submodules` | string | Checkout submodules in the repository. Options are `true` (checkout submodules), `false` (don't checkout submodules), or `recursive` (recursively checkout submodules) | 47 | | `instance` | string | The name of the instance to which the docs should be published (`ops` (default), `dev`) | 48 | 49 | [rewrite-action]: ../../actions/techdocs-rewrite-relative-links/README.md 50 | -------------------------------------------------------------------------------- /.github/workflows/renovate.yml: -------------------------------------------------------------------------------- 1 | name: Renovate 2 | on: 3 | schedule: 4 | # Offset by 12 minutes to avoid busy times on the hour 5 | - cron: 12 */4 * * * 6 | 7 | pull_request: 8 | paths: 9 | - .github/renovate-config.json5 10 | - .github/workflows/renovate.yml 11 | types: 12 | - edited 13 | - opened 14 | - ready_for_review 15 | - synchronize 16 | 17 | push: 18 | branches: 19 | - main 20 | paths: 21 | - .github/renovate-config.json5 22 | - .github/workflows/renovate.yml 23 | 24 | workflow_dispatch: 25 | inputs: 26 | dry-run: 27 | description: "Run Renovate in dry-run mode" 28 | required: false 29 | default: false 30 | type: boolean 31 | 32 | merge_group: 33 | 34 | permissions: 35 | contents: read 36 | 37 | jobs: 38 | renovate: 39 | permissions: 40 | contents: read 41 | id-token: write 42 | runs-on: ubuntu-latest 43 | timeout-minutes: 5 44 | 45 | # We need a secret for the GitHub app, which isn't available for a fork, so 46 | # don't run there. 47 | if: github.event.pull_request.head.repo.full_name == github.repository 48 | 49 | steps: 50 | - name: Harden the runner (Audit all outbound calls) 51 | uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 52 | with: 53 | egress-policy: audit 54 | 55 | - name: Checkout Code 56 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 57 | with: 58 | persist-credentials: false 59 | sparse-checkout: | 60 | .github/renovate-config.json5 61 | actions/get-vault-secrets 62 | 63 | - name: Retrieve renovate secrets 64 | id: get-secrets 65 | uses: ./actions/get-vault-secrets 66 | with: 67 | common_secrets: | 68 | GRAFANA_RENOVATE_APP_ID=grafana-renovate-app:app-id 69 | GRAFANA_RENOVATE_PRIVATE_KEY=grafana-renovate-app:private-key 70 | 71 | - name: Generate token 72 | id: generate-token 73 | uses: actions/create-github-app-token@3ff1caaa28b64c9cc276ce0a02e2ff584f3900c5 # v2.0.2 74 | with: 75 | app-id: ${{ env.GRAFANA_RENOVATE_APP_ID }} 76 | private-key: ${{ env.GRAFANA_RENOVATE_PRIVATE_KEY }} 77 | 78 | - name: Self-hosted Renovate 79 | uses: renovatebot/github-action@8ac70de2fe55752c573155866e30735411e3b61c # v41.0.22 80 | with: 81 | configurationFile: .github/renovate-config.json5 82 | # renovate: datasource=docker depName=ghcr.io/renovatebot/renovate 83 | renovate-version: 39.252.0@sha256:f244c095f6f698e1ced593a8521dd2cc78d22beeaf4fb009450fbc977a2c5b36 84 | token: ${{ steps.generate-token.outputs.token }} 85 | env: 86 | LOG_LEVEL: ${{ github.event_name == 'pull_request' && 'debug' || 'info' }} 87 | # For pull requests, this means we'll get the dependencies of the PR's 88 | # branch, so you can fix/change things and see the results in the PR's 89 | # run. By default, Renovate will clone the main/default branch. 90 | RENOVATE_BASE_BRANCHES: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.ref || null }} 91 | # Dry run if the event is pull_request, or workflow_dispatch AND the dry-run input is true 92 | RENOVATE_DRY_RUN: ${{ (github.event_name == 'pull_request' || (github.event_name == 'workflow_dispatch' && github.event.inputs.dry-run == 'true')) && 'full' || null }} 93 | RENOVATE_PLATFORM: github 94 | RENOVATE_REPOSITORIES: ${{ github.repository }} 95 | RENOVATE_USERNAME: GrafanaRenovateBot 96 | -------------------------------------------------------------------------------- /.github/workflows/scorecards.yml: -------------------------------------------------------------------------------- 1 | # This workflow uses actions that are not certified by GitHub. They are provided 2 | # by a third-party and are governed by separate terms of service, privacy 3 | # policy, and support documentation. 4 | 5 | name: Scorecard supply-chain security 6 | on: 7 | # For Branch-Protection check. Only the default branch is supported. See 8 | # https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection 9 | branch_protection_rule: 10 | # To guarantee Maintained check is occasionally updated. See 11 | # https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained 12 | schedule: 13 | - cron: "20 7 * * 2" 14 | push: 15 | branches: 16 | - main 17 | 18 | # Declare default permissions as read only. 19 | permissions: read-all 20 | 21 | jobs: 22 | analysis: 23 | name: Scorecard analysis 24 | runs-on: ubuntu-latest 25 | permissions: 26 | # Needed to upload the results to code-scanning dashboard. 27 | security-events: write 28 | # Needed to publish results and get a badge (see publish_results below). 29 | id-token: write 30 | contents: read 31 | actions: read 32 | # To allow GraphQL ListCommits to work 33 | issues: read 34 | pull-requests: read 35 | # To detect SAST tools 36 | checks: read 37 | 38 | steps: 39 | - name: Harden the runner (Audit all outbound calls) 40 | uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 41 | with: 42 | egress-policy: audit 43 | 44 | - name: "Checkout code" 45 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 46 | with: 47 | persist-credentials: false 48 | 49 | - name: "Run analysis" 50 | uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0 51 | with: 52 | results_file: results.sarif 53 | results_format: sarif 54 | # (Optional) "write" PAT token. Uncomment the `repo_token` line below if: 55 | # - you want to enable the Branch-Protection check on a *public* repository, or 56 | # - you are installing Scorecards on a *private* repository 57 | # To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat. 58 | # repo_token: ${{ secrets.SCORECARD_TOKEN }} 59 | 60 | # Public repositories: 61 | # - Publish results to OpenSSF REST API for easy access by consumers 62 | # - Allows the repository to include the Scorecard badge. 63 | # - See https://github.com/ossf/scorecard-action#publishing-results. 64 | # For private repositories: 65 | # - `publish_results` will always be set to `false`, regardless 66 | # of the value entered here. 67 | publish_results: true 68 | 69 | # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF 70 | # format to the repository Actions tab. 71 | - name: "Upload artifact" 72 | uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 73 | with: 74 | name: SARIF file 75 | path: results.sarif 76 | retention-days: 5 77 | 78 | # Upload the results to GitHub's code scanning dashboard. 79 | - name: "Upload to code-scanning" 80 | uses: github/codeql-action/upload-sarif@28deaeda66b76a05916b6923827895f2b14ab387 # v3.28.16 81 | with: 82 | sarif_file: results.sarif 83 | -------------------------------------------------------------------------------- /.github/workflows/self-zizmor.yml: -------------------------------------------------------------------------------- 1 | name: zizmor GitHub Actions static analysis 2 | on: 3 | push: 4 | pull_request: 5 | 6 | permissions: 7 | contents: read 8 | 9 | jobs: 10 | zizmor: 11 | name: Run zizmor from current branch (self test) 12 | 13 | permissions: 14 | actions: read 15 | contents: read 16 | 17 | # used in the `job-workflow-ref` job to fetch an OIDC token, which allows 18 | # the run to determine its ref 19 | id-token: write 20 | 21 | pull-requests: write 22 | security-events: write 23 | 24 | uses: ./.github/workflows/reusable-zizmor.yml 25 | -------------------------------------------------------------------------------- /.github/workflows/test-find-pr-for-commit.yml: -------------------------------------------------------------------------------- 1 | name: Test find-pr-for-commit action 2 | on: 3 | push: 4 | branches: 5 | - main 6 | paths: 7 | - actions/find-pr-for-commit/** 8 | - .github/workflows/test-find-pr-for-commit.yml 9 | 10 | pull_request: 11 | paths: 12 | - actions/find-pr-for-commit/** 13 | - .github/workflows/test-find-pr-for-commit.yml 14 | types: 15 | - edited 16 | - opened 17 | - ready_for_review 18 | - synchronize 19 | 20 | permissions: 21 | contents: read 22 | pull-requests: read 23 | 24 | jobs: 25 | test: 26 | # TODO: fix the tests to work with forks 27 | if: github.event.pull_request.head.repo.full_name == github.repository 28 | 29 | strategy: 30 | max-parallel: 1 31 | matrix: 32 | include: 33 | - test_name: "Test current commit by name (${{ github.event_name}})" 34 | commitrev: ${{ github.event_name == 'pull_request' && format('refs/pull/{0}/head', github.event.number) || github.ref }} 35 | # Anything, just checking it has a PR 36 | pr_number_regex: "^[0-9]+$" 37 | 38 | - test_name: "Test current commit by sha (${{ github.event_name}})" 39 | commitrev: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }} 40 | pr_number_regex: "^${{ github.event_name == 'pull_request' && github.event.number || '[0-9]+' }}$" 41 | 42 | - test_name: "Test commit with no PR" 43 | commitrev: "" 44 | pr_number_regex: "^$" 45 | 46 | runs-on: ubuntu-latest 47 | permissions: 48 | contents: read 49 | pull-requests: read 50 | 51 | steps: 52 | - name: Harden the runner (Audit all outbound calls) 53 | uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 54 | with: 55 | egress-policy: audit 56 | 57 | - name: Checkout code 58 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 59 | with: 60 | persist-credentials: false 61 | 62 | - name: ${{ matrix.test_name }} 63 | id: test-find-pr-for-commit 64 | uses: ./actions/find-pr-for-commit 65 | with: 66 | commitrev: ${{ matrix.commitrev }} 67 | 68 | - name: Check PR number 69 | env: 70 | PR_NUMBER: "${{ steps.test-find-pr-for-commit.outputs.pr_number }}" 71 | PR_NUMBER_REGEX: "${{ matrix.pr_number_regex }}" 72 | run: | 73 | set -x 74 | 75 | if ! [[ "${PR_NUMBER}" =~ ${PR_NUMBER_REGEX} ]]; then 76 | echo "Test failed: PR number does not match expected value" 77 | exit 1 78 | fi 79 | 80 | echo "Test passed: PR number matches expected value 🚀" 81 | -------------------------------------------------------------------------------- /.github/workflows/test-get-vault-secrets.yaml: -------------------------------------------------------------------------------- 1 | name: Test get-vault-secrets action 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths: 8 | - "actions/get-vault-secrets/**" 9 | - ".github/workflows/test-get-vault-secrets.yaml" 10 | 11 | pull_request: 12 | paths: 13 | - "actions/get-vault-secrets/**" 14 | - ".github/workflows/test-get-vault-secrets.yaml" 15 | types: 16 | - edited 17 | - opened 18 | - ready_for_review 19 | - synchronize 20 | 21 | merge_group: 22 | 23 | permissions: 24 | contents: read 25 | 26 | jobs: 27 | test: 28 | strategy: 29 | matrix: 30 | instance: 31 | - dev 32 | - ops 33 | - invalid 34 | 35 | permissions: 36 | contents: read 37 | id-token: write 38 | 39 | runs-on: ubuntu-latest 40 | 41 | # The `get-vault-secrets` action only works when run from a `grafana` 42 | # repository, so skip this test if the PR is from a different repository. We 43 | # will still get a run of this workflow for the change before merging, as we 44 | # use merge queues. 45 | if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.owner.login == 'grafana' 46 | 47 | steps: 48 | - name: Harden the runner (Audit all outbound calls) 49 | uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 50 | with: 51 | egress-policy: audit 52 | 53 | - name: Checkout code 54 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 55 | with: 56 | persist-credentials: false 57 | 58 | - name: Test Vault Action 59 | id: test-vault-action 60 | uses: ./actions/get-vault-secrets 61 | continue-on-error: true 62 | with: 63 | vault_instance: ${{ matrix.instance }} 64 | repo_secrets: | 65 | INSTANCE=test-get-vault-secret:instance 66 | 67 | - name: Check secret value is ${{ matrix.instance }} 68 | if: matrix.instance != 'invalid' 69 | run: | 70 | if [[ "${{ env.INSTANCE }}" != "${{ matrix.instance }}" ]]; then 71 | echo "Test failed: secret value does not match vault_instance input" 72 | exit 1 73 | fi 74 | 75 | - name: Ensure 'invalid' errored 76 | if: matrix.instance == 'invalid' && steps.test-vault-action.outcome != 'failure' 77 | run: | 78 | echo "Test failed: 'invalid' should have errored" 79 | exit 1 80 | 81 | bats-test: 82 | runs-on: ubuntu-latest 83 | 84 | permissions: 85 | contents: read 86 | steps: 87 | - name: Harden the runner (Audit all outbound calls) 88 | uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 89 | with: 90 | egress-policy: audit 91 | 92 | - name: Checkout code 93 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 94 | with: 95 | persist-credentials: false 96 | 97 | - name: Setup BATS testing framework 98 | uses: mig4/setup-bats@af9a00deb21b5d795cabfeaa8d9060410377686d # v1.2.0 99 | 100 | - name: Run tests 101 | run: | 102 | cd actions/get-vault-secrets 103 | ./translate-secrets.bats 104 | -------------------------------------------------------------------------------- /.github/workflows/test-lint-pr-title.yml: -------------------------------------------------------------------------------- 1 | name: Lint & test "Lint PR title" action 2 | on: 3 | push: 4 | branches: 5 | - main 6 | paths: 7 | - .github/workflows/test-lint-pr-title.yml 8 | - actions/lint-pr-title/** 9 | 10 | pull_request: 11 | paths: 12 | - .github/workflows/test-lint-pr-title.yml 13 | - actions/lint-pr-title/** 14 | types: 15 | - edited 16 | - opened 17 | - ready_for_review 18 | - synchronize 19 | 20 | merge_group: 21 | 22 | permissions: 23 | contents: read 24 | 25 | jobs: 26 | build-lint-pr-title: 27 | runs-on: ubuntu-latest 28 | permissions: 29 | contents: read 30 | 31 | defaults: 32 | run: 33 | working-directory: actions/lint-pr-title 34 | 35 | steps: 36 | - name: Harden the runner (Audit all outbound calls) 37 | uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 38 | with: 39 | egress-policy: audit 40 | 41 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 42 | with: 43 | persist-credentials: false 44 | 45 | - name: Install bun package manager 46 | uses: oven-sh/setup-bun@735343b667d3e6f658f44d0eca948eb6282f2b76 # v2.0.2 47 | with: 48 | bun-version-file: actions/lint-pr-title/.bun-version 49 | 50 | - name: Install lint-pr-title dependencies 51 | run: bun install --frozen-lockfile 52 | 53 | - name: Lint 54 | run: bun lint 55 | 56 | - name: Test 57 | run: bun test 58 | -------------------------------------------------------------------------------- /.github/workflows/test-login-to-gar.yaml: -------------------------------------------------------------------------------- 1 | name: Test login-to-gar action 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths: 8 | - "actions/login-to-gar/**" 9 | - ".github/workflows/test-login-to-gar.yaml" 10 | 11 | pull_request: 12 | paths: 13 | - "actions/login-to-gar/**" 14 | - ".github/workflows/test-login-to-gar.yaml" 15 | types: 16 | - edited 17 | - opened 18 | - ready_for_review 19 | - synchronize 20 | 21 | merge_group: 22 | 23 | permissions: 24 | contents: read 25 | id-token: write 26 | 27 | jobs: 28 | test: 29 | runs-on: ubuntu-latest 30 | # Don't run for forks - they don't have access to secrets 31 | if: github.event.pull_request.head.repo.full_name == github.repository 32 | steps: 33 | - name: Harden the runner (Audit all outbound calls) 34 | uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 35 | with: 36 | egress-policy: audit 37 | 38 | - name: Checkout code 39 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 40 | with: 41 | persist-credentials: false 42 | 43 | - name: Test Login to GAR Action 44 | id: test-login-to-gar 45 | uses: ./actions/login-to-gar 46 | with: 47 | registry: "us-docker.pkg.dev" 48 | -------------------------------------------------------------------------------- /.github/workflows/test-publish-techdocs.yml: -------------------------------------------------------------------------------- 1 | name: Publish TechDocs (test) 2 | on: 3 | push: 4 | branches: 5 | - main 6 | paths: 7 | - .github/publish-techdocs-testdata/** 8 | - .github/workflows/publish-techdocs.yaml 9 | - .github/workflows/test-publish-techdocs.yml 10 | - .github/workflows/test-techdocs-rewrite-relative-links.yml 11 | - techdocs-rewrite-relative-links/** 12 | 13 | pull_request: 14 | branches: 15 | - main 16 | paths: 17 | - .github/publish-techdocs-testdata/** 18 | - .github/workflows/publish-techdocs.yaml 19 | - .github/workflows/test-publish-techdocs.yml 20 | - .github/workflows/test-techdocs-rewrite-relative-links.yml 21 | - techdocs-rewrite-relative-links/** 22 | types: 23 | - edited 24 | - opened 25 | - ready_for_review 26 | - synchronize 27 | 28 | merge_group: 29 | 30 | concurrency: 31 | group: "${{ github.workflow }}-${{ github.ref }}" 32 | cancel-in-progress: true 33 | 34 | permissions: 35 | contents: read 36 | 37 | jobs: 38 | publish-docs: 39 | uses: ./.github/workflows/publish-techdocs.yaml 40 | 41 | permissions: 42 | contents: read 43 | id-token: write 44 | 45 | with: 46 | default-working-directory: ".github/publish-techdocs-testdata" 47 | kind: component 48 | name: ignored 49 | namespace: default 50 | publish: false 51 | -------------------------------------------------------------------------------- /.github/workflows/test-remove-checkout-credentials.yaml: -------------------------------------------------------------------------------- 1 | name: Test remove-checkout-credentials action 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths: 8 | - "actions/remove-checkout-credentials/**" 9 | - ".github/workflows/test-remove-checkout-credentials.yaml" 10 | 11 | pull_request: 12 | paths: 13 | - "actions/remove-checkout-credentials/**" 14 | - ".github/workflows/test-remove-checkout-credentials.yaml" 15 | types: 16 | - edited 17 | - opened 18 | - ready_for_review 19 | - synchronize 20 | 21 | merge_group: 22 | 23 | permissions: 24 | contents: read 25 | 26 | jobs: 27 | test: 28 | runs-on: ubuntu-latest 29 | steps: 30 | - name: Harden the runner (Audit all outbound calls) 31 | uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 32 | with: 33 | egress-policy: audit 34 | 35 | - name: Checkout code 36 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 37 | with: 38 | persist-credentials: true 39 | 40 | - name: Run cleanup 41 | uses: ./actions/remove-checkout-credentials 42 | 43 | - name: Check if secrets are present 44 | run: | 45 | set +e 46 | if git config get --local --name-only http.https://github.com/.extraheader 2> /dev/null 47 | then 48 | echo "HTTP config is still present!" 49 | exit 1 50 | fi 51 | -------------------------------------------------------------------------------- /.github/workflows/test-setup-argo.yml: -------------------------------------------------------------------------------- 1 | name: Test Setup Argo 2 | on: 3 | push: 4 | branches: 5 | - main 6 | paths: 7 | - actions/setup-argo/** 8 | - .github/workflows/test-setup-argo.yml 9 | 10 | pull_request: 11 | branches: 12 | - main 13 | paths: 14 | - actions/setup-argo/** 15 | - .github/workflows/test-setup-argo.yml 16 | types: 17 | - edited 18 | - opened 19 | - ready_for_review 20 | - synchronize 21 | 22 | merge_group: 23 | 24 | concurrency: 25 | group: "${{ github.workflow }}-${{ github.ref }}" 26 | cancel-in-progress: true 27 | 28 | permissions: 29 | contents: read 30 | 31 | jobs: 32 | setup-argo: 33 | runs-on: ubuntu-latest 34 | 35 | permissions: 36 | contents: read 37 | actions: write # needed for cache 38 | 39 | env: 40 | # generate a unique cache prefix for each test run, so we can test cache behaviour 41 | CACHE_PREFIX: argo-${{ github.run_id }}-${{ github.run_attempt }} 42 | 43 | strategy: 44 | matrix: 45 | cache-hit: [false, true] 46 | max-parallel: 1 47 | 48 | name: "Setup Argo (cache hit: ${{ matrix.cache-hit }})" 49 | 50 | steps: 51 | - name: Harden the runner (Audit all outbound calls) 52 | uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 53 | with: 54 | egress-policy: audit 55 | 56 | - name: Checkout code 57 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 58 | with: 59 | persist-credentials: false 60 | sparse-checkout: | 61 | actions/setup-argo 62 | 63 | - name: "Setup Argo (cache: ${{ matrix.cache-hit }})" 64 | id: setup-argo 65 | uses: ./actions/setup-argo 66 | with: 67 | cache-prefix: ${{ env.CACHE_PREFIX }} 68 | version: 3.5.1 69 | 70 | - name: Assert cache 71 | if: fromJson(steps.setup-argo.outputs.cache-hit) != matrix.cache-hit 72 | run: | 73 | echo "Expected cache hit: '${{ matrix.cache-hit }}' but got '${{ fromJson(steps.setup-argo.outputs.cache-hit) }}'" 74 | exit 1 75 | 76 | - name: Check Argo CLI works 77 | run: argo version 78 | -------------------------------------------------------------------------------- /.github/workflows/test-setup-jrsonnet.yml: -------------------------------------------------------------------------------- 1 | name: Test Setup Jrsonnet 2 | on: 3 | push: 4 | branches: 5 | - main 6 | paths: 7 | - actions/setup-jrsonnet/** 8 | - .github/workflows/test-setup-jrsonnet.yml 9 | 10 | pull_request: 11 | branches: 12 | - main 13 | paths: 14 | - actions/setup-jrsonnet/** 15 | - .github/workflows/test-setup-jrsonnet.yml 16 | types: 17 | - edited 18 | - opened 19 | - ready_for_review 20 | - synchronize 21 | 22 | merge_group: 23 | 24 | concurrency: 25 | group: "${{ github.workflow }}-${{ github.ref }}" 26 | cancel-in-progress: true 27 | 28 | permissions: 29 | contents: read 30 | 31 | jobs: 32 | setup-jrsonnet: 33 | runs-on: ubuntu-latest 34 | permissions: 35 | contents: read 36 | actions: write # needed for cache 37 | env: 38 | # generate a unique cache prefix for each test run, so we can test cache behaviour 39 | CACHE_PREFIX: jrsonnet-${{ github.run_id }}-${{ github.run_attempt }} 40 | 41 | strategy: 42 | matrix: 43 | cache-hit: [false, true] 44 | max-parallel: 1 45 | 46 | name: "Setup Jrsonnet (cache hit: ${{ matrix.cache-hit }})" 47 | 48 | steps: 49 | - name: Harden the runner (Audit all outbound calls) 50 | uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 51 | with: 52 | egress-policy: audit 53 | 54 | - name: Checkout code 55 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 56 | with: 57 | persist-credentials: false 58 | sparse-checkout: | 59 | actions/setup-jrsonnet 60 | 61 | - name: "Setup Jrsonnet (cache: ${{ matrix.cache-hit }})" 62 | id: setup-jrsonnet 63 | uses: ./actions/setup-jrsonnet 64 | with: 65 | cache-prefix: ${{ env.CACHE_PREFIX }} 66 | version: 0.5.0-pre96-test 67 | 68 | - name: Assert cache 69 | if: fromJson(steps.setup-jrsonnet.outputs.cache-hit) != matrix.cache-hit 70 | run: | 71 | echo "Expected cache hit: '${{ matrix.cache-hit }}' but got '${{ fromJson(steps.setup-jrsonnet.outputs.cache-hit) }}'" 72 | exit 1 73 | 74 | - name: Check Jrsonnet CLI works 75 | run: jrsonnet --version 76 | -------------------------------------------------------------------------------- /.github/workflows/test-techdocs-rewrite-relative-links.yaml: -------------------------------------------------------------------------------- 1 | name: Test techdocs-rewrite-relative-links action 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths: 8 | - "actions/techdocs-rewrite-relative-links/**" 9 | - ".github/workflows/test-techdocs-rewrite-relative-links.yaml" 10 | 11 | pull_request: 12 | paths: 13 | - "actions/techdocs-rewrite-relative-links/**" 14 | - ".github/workflows/test-techdocs-rewrite-relative-links.yaml" 15 | types: 16 | - edited 17 | - opened 18 | - ready_for_review 19 | - synchronize 20 | 21 | merge_group: 22 | 23 | permissions: 24 | contents: read 25 | 26 | jobs: 27 | test: 28 | runs-on: ubuntu-latest 29 | permissions: 30 | contents: read 31 | actions: write # needed for cache 32 | 33 | steps: 34 | - name: Harden the runner (Audit all outbound calls) 35 | uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 36 | with: 37 | egress-policy: audit 38 | 39 | - name: Checkout code 40 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 41 | with: 42 | persist-credentials: false 43 | 44 | - name: Setup go 45 | uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0 46 | with: 47 | check-latest: true 48 | go-version: "1.24.2" 49 | cache-dependency-path: "actions/techdocs-rewrite-relative-links/go.sum" 50 | 51 | - name: golangci-lint 52 | uses: golangci/golangci-lint-action@1481404843c368bc19ca9406f87d6e0fc97bdcfd # v7.0.0 53 | with: 54 | version: latest 55 | working-directory: actions/techdocs-rewrite-relative-links 56 | 57 | - name: Test Go code 58 | shell: bash 59 | run: | 60 | set -e 61 | cd actions/techdocs-rewrite-relative-links 62 | go test ./... -v 63 | -------------------------------------------------------------------------------- /.github/workflows/test-zizmor-offline.yml: -------------------------------------------------------------------------------- 1 | name: Test reusable Zizmor in offline mode 2 | on: 3 | push: 4 | pull_request: 5 | 6 | permissions: 7 | contents: read 8 | 9 | jobs: 10 | zizmor-offline: 11 | name: Run zizmor offline for current branch (self test) 12 | 13 | permissions: 14 | actions: read 15 | contents: read 16 | id-token: write 17 | pull-requests: write 18 | security-events: write 19 | 20 | uses: ./.github/workflows/reusable-zizmor.yml 21 | with: 22 | extra-args: --offline --collect=all 23 | -------------------------------------------------------------------------------- /.github/zizmor.yml: -------------------------------------------------------------------------------- 1 | # This is also used as the default configuration for the Zizmor reusable 2 | # workflow. 3 | 4 | rules: 5 | unpinned-uses: 6 | config: 7 | policies: 8 | actions/*: any # trust GitHub 9 | grafana/*: any # trust Grafana 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | -------------------------------------------------------------------------------- /.markdownlint.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/DavidAnson/markdownlint/v0.36.1/schema/markdownlint-config-schema.json", 3 | "line-length": { 4 | "tables": false 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/gitleaks/gitleaks 3 | rev: v8.16.3 4 | hooks: 5 | - id: gitleaks 6 | - repo: https://github.com/golangci/golangci-lint 7 | rev: v1.52.2 8 | hooks: 9 | - id: golangci-lint 10 | - repo: https://github.com/jumanjihouse/pre-commit-hooks 11 | rev: 3.0.0 12 | hooks: 13 | - id: shellcheck 14 | - repo: https://github.com/pre-commit/mirrors-eslint 15 | rev: v8.38.0 16 | hooks: 17 | - id: eslint 18 | - repo: https://github.com/pre-commit/pre-commit-hooks 19 | rev: v4.4.0 20 | hooks: 21 | - id: end-of-file-fixer 22 | - id: trailing-whitespace 23 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # Generated files handled by release-please 2 | 3 | .release-please-manifest.json 4 | **/CHANGELOG.md 5 | 6 | # Generated file 7 | catalog-info.yaml 8 | -------------------------------------------------------------------------------- /.prettierrc.yaml: -------------------------------------------------------------------------------- 1 | trailingComma: all 2 | -------------------------------------------------------------------------------- /.release-please-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "actions/lint-pr-title": "1.2.0", 3 | "actions/get-vault-secrets": "1.2.1", 4 | "actions/dockerhub-login": "1.0.2", 5 | "actions/send-slack-message": "2.0.3", 6 | "actions/push-to-gar-docker": "0.5.1", 7 | "actions/aws-auth": "1.0.2", 8 | "actions/build-push-to-dockerhub": "0.2.0", 9 | "actions/login-to-gar": "0.4.3", 10 | "actions/login-to-gcs": "0.2.1", 11 | "actions/argo-lint": "1.0.2", 12 | "actions/setup-conftest": "1.0.2", 13 | "actions/setup-argo": "1.0.2", 14 | "actions/generate-openapi-clients": "1.0.2", 15 | "actions/push-to-gcs": "0.2.1", 16 | "actions/techdocs-rewrite-relative-links": "1.0.2", 17 | "actions/validate-policy-bot-config": "1.1.1", 18 | "actions/trigger-argo-workflow": "1.1.1", 19 | "actions/setup-jrsonnet": "1.0.1", 20 | "actions/find-pr-for-commit": "1.0.1", 21 | "actions/remove-checkout-credentials": "0.1.0", 22 | "actions/dependabot-auto-triage": "1.0.0", 23 | "actions/get-latest-workflow-artifact": "0.1.0" 24 | } 25 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | # These owners will be the default owners for everything in 2 | # the repo. Unless a later match takes precedence, 3 | # @grafana/platform-productivity will be requested for review when 4 | # someone opens a pull request. 5 | * @grafana/platform-productivity 6 | 7 | # Owned by the Grafana department's Infra O11y Frontend squad 8 | .github/workflows/build-lint-pr.yml @grafana/infra-o11y-frontend 9 | /actions/lint-pr-title/ @grafana/infra-o11y-frontend @grafana/platform-productivity 10 | 11 | # Platform CAT 12 | /actions/generate-openapi-clients @grafana/platform-cat 13 | 14 | # Platform productivity 15 | /.github/workflows/publish-techdocs.yaml @grafana/platform-productivity 16 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Grafana's Shared Workflows Repository 2 | 3 | Welcome to the Shared Workflows repository! This repository contains reusable actions designed to streamline and automate common tasks across multiple departments and external organizations. We appreciate your interest in contributing to our shared efforts. 4 | 5 | ## Scope of `shared-workflows` 6 | 7 | This repository is for generic workflows and actions which can be used across multiple types of projects. For more specialised use-cases, we encourage the use of project- or area-specific shared workflow repositories. 8 | Examples which would fit in here: 9 | 10 | - Push a container image to a Docker registry 11 | - Run security scanners on built artifacts 12 | - Read and write objects to cloud object storage (GCS or S3) 13 | - Lint projects according to a widely-agreed specification such as [Commitlint](https://commitlint.js.org/). 14 | 15 | And those which would be better in project- or area-specific shared workflow repositories: 16 | 17 | - Implement a release process specific to a subset of projects 18 | - Lint project(s) with your team's opinionated toolset 19 | 20 | Get in touch with the maintainers [via an issue](https://github.com/grafana/shared-workflows/issues/new) if you're unsure in a particular case. 21 | 22 | ## Types of Workflows 23 | 24 | Unsure about the difference between a reusable workflow and a composite action? Start [here](https://dev.to/n3wt0n/composite-actions-vs-reusable-workflows-what-is-the-difference-github-actions-11kd). 25 | 26 | ### 1. Reusable Workflows 27 | 28 | The `.github/workflows/` directory contains reusable workflows. Refer to the [GitHub documentation](https://docs.github.com/en/actions/using-workflows/reusing-workflows) for more info. 29 | 30 | ### 2. Composite Actions 31 | 32 | The `actions/` directory contains composite actions. Refer to the [GitHub documentation](https://docs.github.com/en/actions/creating-actions/about-custom-actions#composite-actions) for more info. 33 | 34 | ## Contribution Guidelines 35 | 36 | 1. **Fork the Repository:** Start by forking the repository to your GitHub account. 37 | 38 | 2. **Clone the Fork:** Clone your forked repository to your local machine. 39 | 40 | 3. **Create a Branch:** Create a new branch for your contribution. Use a descriptive name related to the changes you're making. 41 | 42 | 4. **Make Changes:** Make your desired changes to the codebase. 43 | 44 | 5. **Write Tests:** Where it makes sense, please add tests. See `actions/techdocs-rewrite-relative-links` as an example. 45 | 46 | 6. **Document Changes:** Document your changes in a `README.md` file. Try to follow the examples set forward in other READMEs. 47 | 48 | 7. **Commit Changes:** Commit your changes with clear and concise commit messages. 49 | 50 | 8. **Push Changes:** Push your changes to your forked repository. 51 | 52 | 9. **Submit a Pull Request:** Submit a pull request to the main repository. Ensure that your pull request is detailed and includes information about the changes made. 53 | 54 | 10. **Check CI:** Check your pull request to verify that any CI processes are passing. 55 | 56 | 11. **Review Process:** Your pull request will be reviewed by the Grafana Labs' platform-productivity squad. Make any requested changes or address any feedback during this process. 57 | 58 | 12. **Contributor License Agreement (CLA):** Before we can accept your pull request, you need to sign [Grafana's CLA](https://grafana.com/docs/grafana/latest/developers/cla/). If you haven't, our CLA assistant prompts you to when you create your pull request. 59 | 60 | ## Code of Conduct 61 | 62 | We uphold a code of conduct to ensure a respectful and inclusive environment for all contributors. Please review Grafana's [Code of Conduct](https://github.com/grafana/grafana/blob/main/CODE_OF_CONDUCT.md) before contributing. 63 | 64 | ## Contact Us 65 | 66 | If you have any questions or need assistance, feel free to [create an issue](https://github.com/grafana/shared-workflows/issues). 67 | 68 | Thank you for contributing to our Shared Workflows repository! 69 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: catalog-info.yaml 2 | catalog-info.yaml: 3 | cd scripts/generate-catalog-info && \ 4 | go run . -root-dir ../../ -output-path ../../catalog-info.yaml 5 | -------------------------------------------------------------------------------- /actions/argo-lint/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [1.0.2](https://github.com/grafana/shared-workflows/compare/argo-lint-v1.0.1...argo-lint/v1.0.2) (2025-06-04) 4 | 5 | 6 | ### 🐛 Bug Fixes 7 | 8 | * ensure every action disables git credential persistence ([#821](https://github.com/grafana/shared-workflows/issues/821)) ([31ebf3f](https://github.com/grafana/shared-workflows/commit/31ebf3f8e5d0f8709e6ec4ef73b39dd2bd08f959)) 9 | 10 | 11 | ### 📝 Documentation 12 | 13 | * update all readmes to replace hyphen with slash ([#1008](https://github.com/grafana/shared-workflows/issues/1008)) ([472df76](https://github.com/grafana/shared-workflows/commit/472df76fb1cbb92a17fb9e055bdf0d1399109ee3)) 14 | 15 | 16 | ### 🔧 Miscellaneous Chores 17 | 18 | * **main:** release push-to-gar-docker 0.3.0 ([#794](https://github.com/grafana/shared-workflows/issues/794)) ([a7bc536](https://github.com/grafana/shared-workflows/commit/a7bc5367c4a91c389526d58839d8f6224dba4dcc)) 19 | 20 | ## [1.0.1](https://github.com/grafana/shared-workflows/compare/argo-lint-v1.0.0...argo-lint-v1.0.1) (2025-01-29) 21 | 22 | 23 | ### 🔧 Miscellaneous Chores 24 | 25 | * update readme when a new release is available ([#548](https://github.com/grafana/shared-workflows/issues/548)) ([9bf9163](https://github.com/grafana/shared-workflows/commit/9bf9163126c44247bcee6b6b9390eb488f9ead53)) 26 | 27 | ## 1.0.0 (2024-11-28) 28 | 29 | 30 | ### 🎉 Features 31 | 32 | * add argo-lint and install-argo-cli action ([#171](https://github.com/grafana/shared-workflows/issues/171)) ([d848da2](https://github.com/grafana/shared-workflows/commit/d848da21d310b2a847a73457059b5a2d93d9f154)) 33 | 34 | 35 | ### 🐛 Bug Fixes 36 | 37 | * **argo-lint:** fallback to hardcode action repo ([#213](https://github.com/grafana/shared-workflows/issues/213)) ([c663230](https://github.com/grafana/shared-workflows/commit/c6632305ef48112fe6b1aad26ecf2b32a743bda9)) 38 | 39 | 40 | ### 🔧 Miscellaneous Chores 41 | 42 | * **deps:** update actions/checkout action to v4.1.7 ([#244](https://github.com/grafana/shared-workflows/issues/244)) ([1d5fba5](https://github.com/grafana/shared-workflows/commit/1d5fba52e7cb2780dfd1af758e1d84e35ce6e8f7)) 43 | * **deps:** update actions/checkout action to v4.2.0 ([#313](https://github.com/grafana/shared-workflows/issues/313)) ([ba6268c](https://github.com/grafana/shared-workflows/commit/ba6268c6beef0ab5b461f45eef4cfe1b4e6d6013)) 44 | * **deps:** update actions/checkout action to v4.2.1 ([#445](https://github.com/grafana/shared-workflows/issues/445)) ([c72e039](https://github.com/grafana/shared-workflows/commit/c72e039d656ea7db5cbcfd98dffd0f8554e1f029)) 45 | * **deps:** update actions/checkout action to v4.2.2 ([#498](https://github.com/grafana/shared-workflows/issues/498)) ([7c6dbe2](https://github.com/grafana/shared-workflows/commit/7c6dbe23c5fd8f3ab5863fb0e3f9d95de621b746)) 46 | 47 | 48 | ### ♻️ Code Refactoring 49 | 50 | * **setup-argo:** refactor following feedback ([#215](https://github.com/grafana/shared-workflows/issues/215)) ([64a196a](https://github.com/grafana/shared-workflows/commit/64a196a127bcfe135cf6152a387db2024efc3044)) 51 | -------------------------------------------------------------------------------- /actions/argo-lint/README.md: -------------------------------------------------------------------------------- 1 | # Lint Argo 2 | 3 | Shared workflow to lint Argo workflow files. 4 | 5 | ## Example 6 | 7 | 8 | 9 | ``` 10 | uses: grafana/shared-workflows/actions/argo-lint@argo-lint/v1.0.2 11 | with: 12 | path: /path/to/files # Paths to files for linting 13 | 14 | ``` 15 | 16 | 17 | -------------------------------------------------------------------------------- /actions/argo-lint/action.yaml: -------------------------------------------------------------------------------- 1 | name: Lint Argo Workflow files 2 | description: Lint Argo workflow files 3 | 4 | inputs: 5 | path: 6 | description: | 7 | Path to files for linting. 8 | required: true 9 | 10 | runs: 11 | using: composite 12 | 13 | steps: 14 | - name: Checkout 15 | env: 16 | # In a composite action, these two need to be indirected via the 17 | # environment, as per the GitHub actions documentation: 18 | # https://docs.github.com/en/actions/learn-github-actions/contexts 19 | action_repo: "${{ github.action_repository || 'grafana/shared-workflows' }}" 20 | action_ref: ${{ github.action_ref }} 21 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 22 | with: 23 | repository: ${{ env.action_repo }} 24 | ref: ${{ env.action_ref }} 25 | path: _shared-workflows-argo-lint 26 | persist-credentials: false 27 | 28 | - name: Setup Argo 29 | uses: ./_shared-workflows-argo-lint/actions/setup-argo 30 | 31 | - name: Run 32 | env: 33 | WORKFLOW_PATH: ${{ inputs.path }} 34 | shell: bash 35 | run: argo lint --offline "${WORKFLOW_PATH}" 36 | -------------------------------------------------------------------------------- /actions/aws-auth/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [1.0.2](https://github.com/grafana/shared-workflows/compare/aws-auth-v1.0.1...aws-auth/v1.0.2) (2025-06-04) 4 | 5 | 6 | ### 📝 Documentation 7 | 8 | * fix wrong aws-auth reference in readme ([#731](https://github.com/grafana/shared-workflows/issues/731)) ([c0ae660](https://github.com/grafana/shared-workflows/commit/c0ae660365599f4f1a8550c941e08d4a6de268e5)) 9 | * **multiple-actions:** move permissions to job level in workflow examples ([49c90b1](https://github.com/grafana/shared-workflows/commit/49c90b10fcbce463983bed45932cf468b8bd06ce)) 10 | * **multiple-actions:** move permissions to job level in workflows ([#969](https://github.com/grafana/shared-workflows/issues/969)) ([49c90b1](https://github.com/grafana/shared-workflows/commit/49c90b10fcbce463983bed45932cf468b8bd06ce)) 11 | * update all readmes to replace hyphen with slash ([#1008](https://github.com/grafana/shared-workflows/issues/1008)) ([472df76](https://github.com/grafana/shared-workflows/commit/472df76fb1cbb92a17fb9e055bdf0d1399109ee3)) 12 | 13 | 14 | ### 🔧 Miscellaneous Chores 15 | 16 | * **main:** release push-to-gar-docker 0.3.0 ([#794](https://github.com/grafana/shared-workflows/issues/794)) ([a7bc536](https://github.com/grafana/shared-workflows/commit/a7bc5367c4a91c389526d58839d8f6224dba4dcc)) 17 | 18 | ## [1.0.1](https://github.com/grafana/shared-workflows/compare/aws-auth-v1.0.0...aws-auth-v1.0.1) (2025-01-29) 19 | 20 | 21 | ### 🔧 Miscellaneous Chores 22 | 23 | * update readme when a new release is available ([#548](https://github.com/grafana/shared-workflows/issues/548)) ([9bf9163](https://github.com/grafana/shared-workflows/commit/9bf9163126c44247bcee6b6b9390eb488f9ead53)) 24 | 25 | ## 1.0.0 (2024-11-27) 26 | 27 | 28 | ### 🎉 Features 29 | 30 | * **actions:** Create `aws-auth` composite action ([#67](https://github.com/grafana/shared-workflows/issues/67)) ([49b9885](https://github.com/grafana/shared-workflows/commit/49b9885e467b0544c76602d4e8b8ee342f6ea96b)) 31 | * **aws-auth:** add workflow_ref claim ([#227](https://github.com/grafana/shared-workflows/issues/227)) ([c0e3298](https://github.com/grafana/shared-workflows/commit/c0e329819eb62c2cfb5611a56289a2017066b1e7)) 32 | 33 | 34 | ### 🐛 Bug Fixes 35 | 36 | * **aws-auth:** make script executable ([#485](https://github.com/grafana/shared-workflows/issues/485)) ([dfa5e58](https://github.com/grafana/shared-workflows/commit/dfa5e58bc01ab959770bb57a434c63fceb9a0783)) 37 | * **aws-auth:** no such file for resolve-aws-region.sh ([#492](https://github.com/grafana/shared-workflows/issues/492)) ([84db55e](https://github.com/grafana/shared-workflows/commit/84db55e4f41ce257b365f8236ea6b2ce849da236)) 38 | * **aws-auth:** support checked out action mode ([#484](https://github.com/grafana/shared-workflows/issues/484)) ([67c54c7](https://github.com/grafana/shared-workflows/commit/67c54c781187c4cf4c03a937b2029e03e82c19e4)) 39 | 40 | 41 | ### 📝 Documentation 42 | 43 | * **aws auth:** Mention `event_name` in passed claims ([#144](https://github.com/grafana/shared-workflows/issues/144)) ([28a818b](https://github.com/grafana/shared-workflows/commit/28a818be69fe2838d577205e53c9e8c411e68e20)) 44 | * **aws-auth action:** Add example of IAM role setup ([#72](https://github.com/grafana/shared-workflows/issues/72)) ([014f020](https://github.com/grafana/shared-workflows/commit/014f020ca34fedea0827998db586c87125a778eb)) 45 | * **aws-auth action:** fix permissions typo in example ([#75](https://github.com/grafana/shared-workflows/issues/75)) ([27696f8](https://github.com/grafana/shared-workflows/commit/27696f87003ba95a885a222367934a2e5e25848d)) 46 | * **aws-auth:** use ref instead of workflow_ref ([#456](https://github.com/grafana/shared-workflows/issues/456)) ([f0dd348](https://github.com/grafana/shared-workflows/commit/f0dd3480fa3e657d741dd9e8d9b999cfb61fc713)) 47 | 48 | 49 | ### 🤖 Continuous Integration 50 | 51 | * add workflow that lints shell scripts with ShellCheck ([#147](https://github.com/grafana/shared-workflows/issues/147)) ([570898e](https://github.com/grafana/shared-workflows/commit/570898eda6d4fb6c0e4d45a24bf9681c89a12aa6)) 52 | 53 | 54 | ### 🔧 Miscellaneous Chores 55 | 56 | * **deps:** update catnekaise/cognito-idpool-auth action to v1.0.2 ([#246](https://github.com/grafana/shared-workflows/issues/246)) ([a4c9c10](https://github.com/grafana/shared-workflows/commit/a4c9c10b1ed2b863ab85e1f655fc8dc960382271)) 57 | -------------------------------------------------------------------------------- /actions/aws-auth/action.yaml: -------------------------------------------------------------------------------- 1 | name: Authenticate to AWS 2 | description: Authenticate to AWS from GitHub Actions via OpenID Connect 3 | 4 | inputs: 5 | aws-region: 6 | default: "us-east-2" 7 | required: true 8 | description: "AWS region" 9 | role-arn: 10 | default: "" 11 | required: true 12 | description: "ARN of workload role" 13 | pass-claims: 14 | default: "event_name, repository_owner, repository_name, job_workflow_ref, ref" 15 | required: true 16 | description: "`, `-separated claims from GitHub ID token to make available to `role-arn`" 17 | set-creds-in-environment: 18 | default: "true" 19 | required: false 20 | description: "Set environment variables for AWS CLI and SDKs" 21 | role-duration-seconds: 22 | default: "3600" 23 | required: false 24 | description: "Role duration in seconds" 25 | checkout-actions-repository-path: 26 | description: "The path in the filesystem where this repository has been checked out. This is mandatory for setups where executing this action inside a local clone of the repository." 27 | 28 | outputs: 29 | aws_access_key_id: 30 | description: "AWS Access Key Id" 31 | value: ${{ steps.auth.outputs.aws_access_key_id }} 32 | aws_secret_access_key: 33 | description: "AWS Secret Access Key" 34 | value: ${{ steps.auth.outputs.aws_secret_access_key }} 35 | aws_session_token: 36 | description: "AWS Session Name" 37 | value: ${{ steps.auth.outputs.aws_session_token }} 38 | aws_region: 39 | description: "AWS Region" 40 | value: ${{ steps.aws_region.outputs.value }} 41 | cognito_identity_oidc_access_token: 42 | description: "Cognito Identity OIDC Access Token" 43 | value: ${{ steps.auth.outputs.cognito_identity_oidc_access_token }} 44 | 45 | runs: 46 | using: composite 47 | steps: 48 | - id: auth 49 | uses: catnekaise/cognito-idpool-auth@41fcec30f55c069bc59f5773077c37477c743bf6 # v1.0.2 50 | with: 51 | cognito-identity-pool-id: "us-east-2:3a4bca79-07af-4921-a9fb-e21475708406" 52 | auth-flow: "enhanced" 53 | aws-region: "us-east-2" 54 | audience: "github-actions-cognito-identity-pool" 55 | aws-account-id: "590183704419" 56 | chain-role-session-name: "GitHubActions" 57 | chain-role-arn: "${{ inputs.role-arn }}" 58 | chain-role-duration-seconds: "${{ inputs.role-duration-seconds }}" 59 | chain-pass-claims: "${{ inputs.pass-claims }}" 60 | chain-set-in-environment: "${{ inputs.set-creds-in-environment }}" 61 | 62 | - id: aws_region 63 | shell: bash 64 | env: 65 | AWS_REGION: "${{ inputs.aws-region }}" 66 | AWS_DEFAULT_REGION: "${{ inputs.aws-region }}" 67 | REPOSITORY_PATH: "${{ inputs.checkout-actions-repository-path }}" 68 | run: | 69 | if [[ ! -z "${REPOSITORY_PATH}" ]]; then 70 | cd ${REPOSITORY_PATH}/actions/aws-auth 71 | else 72 | cd "${{ github.action_path }}" 73 | fi 74 | ./resolve-aws-region.sh 75 | -------------------------------------------------------------------------------- /actions/aws-auth/resolve-aws-region.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Pulled from catnekaise/cognito-idpool-auth/action.yml 3 | # https://github.com/catnekaise/cognito-idpool-auth/blob/83ae9e159de469b3acd87ecb361d6b5957ee35ae/action.yml#L192-L227 4 | value="" 5 | 6 | if [ -n "${AWS_REGION}" ] && [ -n "${AWS_DEFAULT_REGION}" ]; then 7 | value="$AWS_REGION" 8 | fi 9 | 10 | readonly value 11 | 12 | if [ -z "${value}" ]; then 13 | echo 'Unable to resolve what AWS region to use' 14 | exit 1 15 | fi 16 | 17 | # Some-effort validation of aws region 18 | if echo "${value}" | grep -Eqv '^[a-z]{2}-[a-z]{4,9}-[0-9]$'; then 19 | echo 'Resolved value for AWS region is invalid' 20 | exit 1 21 | fi 22 | 23 | echo "value=${value}" >> "${GITHUB_OUTPUT}" 24 | echo "AWS_REGION=${AWS_REGION}" >> "${GITHUB_ENV}" 25 | echo "AWS_DEFAULT_REGION=${AWS_DEFAULT_REGION}" >> "${GITHUB_ENV}" 26 | -------------------------------------------------------------------------------- /actions/build-push-to-dockerhub/action.yaml: -------------------------------------------------------------------------------- 1 | name: Build & Publish Docker image 2 | description: Build and publish docker images to DockerHub 3 | 4 | inputs: 5 | repository: 6 | description: | 7 | The caller workflow's repository 8 | tags: 9 | description: | 10 | List of Docker images to be pushed. 11 | required: true 12 | context: 13 | description: | 14 | Path to the Docker build context. 15 | default: "." 16 | platforms: 17 | description: | 18 | List of platforms to build the image for 19 | required: false 20 | push: 21 | description: | 22 | Also push the generated images to DockerHub 23 | default: "false" 24 | file: 25 | description: | 26 | The dockerfile to use. 27 | required: false 28 | build-args: 29 | description: | 30 | List of arguments necessary for the Docker image to be built. 31 | required: false 32 | default: "" 33 | target: 34 | description: | 35 | Target stage to build 36 | required: false 37 | cache-from: 38 | description: | 39 | Where cache should be fetched from 40 | required: false 41 | default: "type=gha" 42 | cache-to: 43 | description: | 44 | Where cache should be stored to 45 | required: false 46 | default: "type=gha,mode=max" 47 | docker-buildx-driver: 48 | description: | 49 | The driver to use for Docker Buildx 50 | required: false 51 | default: "docker-container" 52 | secrets: 53 | description: | 54 | Secrets to expose to the build. Only needed when authenticating to private repositories outside the repository in which the image is being built. 55 | required: false 56 | 57 | runs: 58 | using: composite 59 | steps: 60 | # See this conversation for more context as to why we don't want to allow pushes on pull requests 61 | # https://github.com/grafana/shared-workflows/pull/143#discussion_r1628314620 62 | - name: Check if push is allowed 63 | if: ${{ inputs.push == 'true' && github.event_name == 'pull_request' }} 64 | shell: sh 65 | run: | 66 | >&2 echo "Publishing to DockerHub is not allowed on pull_request events." 67 | >&2 echo "If you still want to build images without pushing them, set the push input to false." 68 | exit 1 69 | 70 | - name: Checkout shared workflows 71 | env: 72 | # In a composite action, these two need to be indirected via the 73 | # environment, as per the GitHub actions documentation: 74 | # https://docs.github.com/en/actions/learn-github-actions/contexts 75 | action_repo: ${{ github.action_repository }} 76 | action_ref: ${{ github.action_ref }} 77 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 78 | with: 79 | repository: ${{ env.action_repo }} 80 | ref: ${{ env.action_ref }} 81 | path: _shared-workflows-build-push-to-dockerhub 82 | persist-credentials: false 83 | 84 | - name: Login to DockerHub 85 | if: ${{ inputs.push == 'true' }} 86 | uses: ./_shared-workflows-build-push-to-dockerhub/actions/dockerhub-login 87 | 88 | # If platforms is specified then also initialize buildx and qemu: 89 | - name: Set up QEMU 90 | if: inputs.platforms 91 | uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0 92 | 93 | - name: Set up Docker Buildx 94 | uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0 95 | with: 96 | driver: ${{ inputs.docker-buildx-driver }} 97 | buildkitd-config: ${{ runner.environment == 'self-hosted' && '/etc/buildkitd.toml' || '' }} 98 | 99 | - name: Extract metadata (tags, labels) for Docker 100 | id: meta 101 | uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0 102 | with: 103 | images: ${{ inputs.repository }} 104 | tags: ${{ inputs.tags }} 105 | 106 | - name: Build and push Docker image 107 | uses: docker/build-push-action@14487ce63c7a62a4a324b0bfb37086795e31c6c1 # v6.16.0 108 | with: 109 | context: ${{ inputs.context }} 110 | platforms: ${{ inputs.platforms }} 111 | push: ${{ inputs.push }} 112 | tags: ${{ steps.meta.outputs.tags }} 113 | labels: ${{ steps.meta.outputs.labels }} 114 | file: ${{ inputs.file }} 115 | build-args: ${{ inputs.build-args }} 116 | target: ${{ inputs.target }} 117 | cache-from: ${{ inputs.cache-from }} 118 | cache-to: ${{ inputs.cache-to }} 119 | secrets: ${{ inputs.secrets }} 120 | -------------------------------------------------------------------------------- /actions/dependabot-auto-triage/.bun-version: -------------------------------------------------------------------------------- 1 | 1.2.8 2 | -------------------------------------------------------------------------------- /actions/dependabot-auto-triage/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /actions/dependabot-auto-triage/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 1.0.0 (2025-06-04) 4 | 5 | 6 | ### 🎉 Features 7 | 8 | * **dependabot-auto-triage:** add dependabot-auto-triage workflow ([#927](https://github.com/grafana/shared-workflows/issues/927)) ([e663186](https://github.com/grafana/shared-workflows/commit/e663186a322e94e0b71c924589aaa9d8e4021a82)) 9 | 10 | 11 | ### 📝 Documentation 12 | 13 | * update all readmes to replace hyphen with slash ([#1008](https://github.com/grafana/shared-workflows/issues/1008)) ([472df76](https://github.com/grafana/shared-workflows/commit/472df76fb1cbb92a17fb9e055bdf0d1399109ee3)) 14 | 15 | 16 | ### 🔧 Miscellaneous Chores 17 | 18 | * **main:** release push-to-gar-docker 0.3.0 ([#794](https://github.com/grafana/shared-workflows/issues/794)) ([a7bc536](https://github.com/grafana/shared-workflows/commit/a7bc5367c4a91c389526d58839d8f6224dba4dcc)) 19 | -------------------------------------------------------------------------------- /actions/dependabot-auto-triage/action.yml: -------------------------------------------------------------------------------- 1 | name: "Auto Dismiss Dependabot Alerts" 2 | description: "Auto dismiss Dependabot alerts based on manifest path" 3 | inputs: 4 | token: 5 | description: "GitHub token with permissions to dismiss alerts" 6 | required: true 7 | alert-types: 8 | description: 'Comma-separated list of alert types to dismiss (default: "dependency")' 9 | required: false 10 | default: "dependency" 11 | paths: 12 | description: "Multi-line list of glob patterns to match manifest paths to dismiss" 13 | required: true 14 | # Example: | 15 | # terraform/modules/**/*.json 16 | # docker/vendor/** 17 | dismissal-comment: 18 | description: "Default comment to add when dismissing alerts" 19 | required: false 20 | default: "Auto-dismissed based on manifest path configuration" 21 | dismissal-reason: 22 | description: "Default reason for dismissal" 23 | required: false 24 | default: "not_used" 25 | # Options: 'fix_started', 'inaccurate', 'no_bandwidth', 'not_used', 'tolerable_risk' 26 | 27 | runs: 28 | using: "composite" 29 | steps: 30 | - name: Install bun package manager 31 | uses: oven-sh/setup-bun@4bc047ad259df6fc24a6c9b0f9a0cb08cf17fbe5 # v2.0.1 32 | with: 33 | bun-version-file: ${{ github.action_path }}/.bun-version 34 | 35 | - name: Install dependencies 36 | shell: bash 37 | working-directory: ${{ github.action_path }} 38 | run: | 39 | bun install --frozen-lockfile --production 40 | 41 | - name: Auto dismiss Dependabot alerts 42 | shell: bash 43 | working-directory: ${{ github.action_path }} 44 | env: 45 | GITHUB_TOKEN: ${{ inputs.token }} 46 | INPUT_ALERT_TYPES: ${{ inputs.alert-types }} 47 | INPUT_PATHS: ${{ inputs.paths }} 48 | INPUT_DISMISSAL_COMMENT: ${{ inputs.dismissal-comment }} 49 | INPUT_DISMISSAL_REASON: ${{ inputs.dismissal-reason }} 50 | NODE_ENV: "production" 51 | run: | 52 | bun run src/index.ts 53 | -------------------------------------------------------------------------------- /actions/dependabot-auto-triage/eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import eslint from "@eslint/js"; 2 | import eslintPluginJest from "eslint-plugin-jest"; 3 | import eslintPluginPrettierRecommended from "eslint-plugin-prettier/recommended"; 4 | import js from "@eslint/js"; 5 | import tseslint from "typescript-eslint"; 6 | 7 | export default tseslint.config( 8 | js.configs.recommended, 9 | eslint.configs.recommended, 10 | ...tseslint.configs.strictTypeChecked, 11 | eslintPluginPrettierRecommended, 12 | { 13 | // Allow unused vars if they start with an underscore 14 | rules: { 15 | "@typescript-eslint/no-unused-vars": [ 16 | "error", 17 | { 18 | varsIgnorePattern: "^_", 19 | argsIgnorePattern: "^_", 20 | }, 21 | ], 22 | }, 23 | languageOptions: { 24 | parserOptions: { 25 | projectService: true, 26 | }, 27 | }, 28 | }, 29 | { 30 | files: ["**/*.js", "**/*.mjs"], 31 | ...tseslint.configs.disableTypeChecked, 32 | }, 33 | { 34 | files: ["test/**/*.ts"], 35 | ...eslintPluginJest.configs["flat/recommended"], 36 | }, 37 | { 38 | ignores: ["coverage/", "dist/", "node_modules/"], 39 | }, 40 | ); 41 | -------------------------------------------------------------------------------- /actions/dependabot-auto-triage/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "auto-dismiss-dependabot-alerts", 3 | "version": "0.1.0", 4 | "description": "GitHub action to auto-dismiss Dependabot alerts based on manifest path patterns", 5 | "main": "src/index.ts", 6 | "type": "module", 7 | "private": true, 8 | "scripts": { 9 | "typecheck": "tsc --noEmit", 10 | "lint": "eslint .", 11 | "test": "bun test" 12 | }, 13 | "dependencies": { 14 | "@octokit/request-error": "^5.0.1", 15 | "@octokit/rest": "^19.0.8", 16 | "minimatch": "^9.0.3" 17 | }, 18 | "devDependencies": { 19 | "@eslint/js": "^9.26.0", 20 | "@types/bun": "^1.2.12", 21 | "eslint-config-prettier": "^10.1.3", 22 | "eslint-plugin-jest": "^28.11.0", 23 | "eslint-plugin-prettier": "^5.4.0", 24 | "typescript": "^5.8.3", 25 | "typescript-eslint": "^8.32.0" 26 | }, 27 | "engines": { 28 | "bun": "^1.0.0" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /actions/dependabot-auto-triage/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "compilerOptions": { 4 | "types": ["bun-types"], 5 | "allowJs": true, 6 | "checkJs": true, 7 | "esModuleInterop": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "module": "es2022", 10 | "moduleResolution": "Bundler", 11 | "newLine": "lf", 12 | "noImplicitAny": true, 13 | "outDir": "./dist", 14 | "resolveJsonModule": true, 15 | "skipLibCheck": true, 16 | "sourceMap": true, 17 | "strict": true, 18 | "strictNullChecks": true, 19 | "target": "es2022" 20 | }, 21 | "include": ["**/*.ts"] 22 | } 23 | -------------------------------------------------------------------------------- /actions/dockerhub-login/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [1.0.2](https://github.com/grafana/shared-workflows/compare/dockerhub-login-v1.0.1...dockerhub-login/v1.0.2) (2025-06-04) 4 | 5 | 6 | ### 🐛 Bug Fixes 7 | 8 | * ensure every action disables git credential persistence ([#821](https://github.com/grafana/shared-workflows/issues/821)) ([31ebf3f](https://github.com/grafana/shared-workflows/commit/31ebf3f8e5d0f8709e6ec4ef73b39dd2bd08f959)) 9 | 10 | 11 | ### 📝 Documentation 12 | 13 | * **multiple-actions:** move permissions to job level in workflow examples ([49c90b1](https://github.com/grafana/shared-workflows/commit/49c90b10fcbce463983bed45932cf468b8bd06ce)) 14 | * **multiple-actions:** move permissions to job level in workflows ([#969](https://github.com/grafana/shared-workflows/issues/969)) ([49c90b1](https://github.com/grafana/shared-workflows/commit/49c90b10fcbce463983bed45932cf468b8bd06ce)) 15 | * update all readmes to replace hyphen with slash ([#1008](https://github.com/grafana/shared-workflows/issues/1008)) ([472df76](https://github.com/grafana/shared-workflows/commit/472df76fb1cbb92a17fb9e055bdf0d1399109ee3)) 16 | 17 | 18 | ### 🔧 Miscellaneous Chores 19 | 20 | * **deps:** update docker/login-action action to v3.4.0 ([#848](https://github.com/grafana/shared-workflows/issues/848)) ([117d851](https://github.com/grafana/shared-workflows/commit/117d8511cbc5da0337972deeb400c4298b057af3)) 21 | * **main:** release push-to-gar-docker 0.3.0 ([#794](https://github.com/grafana/shared-workflows/issues/794)) ([a7bc536](https://github.com/grafana/shared-workflows/commit/a7bc5367c4a91c389526d58839d8f6224dba4dcc)) 22 | 23 | ## [1.0.1](https://github.com/grafana/shared-workflows/compare/dockerhub-login-v1.0.0...dockerhub-login-v1.0.1) (2025-01-28) 24 | 25 | 26 | ### 🔧 Miscellaneous Chores 27 | 28 | * update readme when a new release is available ([#548](https://github.com/grafana/shared-workflows/issues/548)) ([9bf9163](https://github.com/grafana/shared-workflows/commit/9bf9163126c44247bcee6b6b9390eb488f9ead53)) 29 | 30 | ## 1.0.0 (2024-10-16) 31 | 32 | 33 | ### 🔧 Miscellaneous Chores 34 | 35 | * Bump upstream docker actions ([#51](https://github.com/grafana/shared-workflows/issues/51)) ([f33ebd9](https://github.com/grafana/shared-workflows/commit/f33ebd946aa2bcd994fb26afdedb575131a5b0b3)) 36 | * **deps:** update actions/checkout action to v4.1.7 ([#244](https://github.com/grafana/shared-workflows/issues/244)) ([1d5fba5](https://github.com/grafana/shared-workflows/commit/1d5fba52e7cb2780dfd1af758e1d84e35ce6e8f7)) 37 | * **deps:** update actions/checkout action to v4.2.0 ([#313](https://github.com/grafana/shared-workflows/issues/313)) ([ba6268c](https://github.com/grafana/shared-workflows/commit/ba6268c6beef0ab5b461f45eef4cfe1b4e6d6013)) 38 | * **deps:** update actions/checkout action to v4.2.1 ([#445](https://github.com/grafana/shared-workflows/issues/445)) ([c72e039](https://github.com/grafana/shared-workflows/commit/c72e039d656ea7db5cbcfd98dffd0f8554e1f029)) 39 | * **deps:** update docker/login-action action to v3.3.0 ([#254](https://github.com/grafana/shared-workflows/issues/254)) ([a678ac5](https://github.com/grafana/shared-workflows/commit/a678ac51c04a71178b65744276e210a6ad61b096)) 40 | -------------------------------------------------------------------------------- /actions/dockerhub-login/README.md: -------------------------------------------------------------------------------- 1 | # dockerhub-login 2 | 3 | This is a composite GitHub Action, used to login to the grafanabot DockerHub account 4 | It uses `get-vault-secrets` action to get the DockerHub username and password from Vault. 5 | 6 | Example of how to use this action in a repository: 7 | 8 | 9 | 10 | ```yaml 11 | name: Push to DockerHub 12 | on: 13 | pull_request: 14 | 15 | jobs: 16 | build: 17 | runs-on: ubuntu-latest 18 | permissions: 19 | contents: read 20 | id-token: write 21 | steps: 22 | - name: Login to DockerHub 23 | uses: grafana/shared-workflows/actions/dockerhub-login@dockerhub-login/v1.0.2 24 | - name: Build and push 25 | run: make build && make push 26 | ``` 27 | 28 | 29 | -------------------------------------------------------------------------------- /actions/dockerhub-login/action.yaml: -------------------------------------------------------------------------------- 1 | name: Login to DockerHub 2 | description: Using the shared Grafana Labs DockerHub credentials, log in to DockerHub 3 | 4 | runs: 5 | using: composite 6 | steps: 7 | - name: Checkout shared workflows 8 | env: 9 | # In a composite action, these two need to be indirected via the 10 | # environment, as per the GitHub actions documentation: 11 | # https://docs.github.com/en/actions/learn-github-actions/contexts 12 | action_repo: ${{ github.action_repository }} 13 | action_ref: ${{ github.action_ref }} 14 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 15 | with: 16 | repository: ${{ env.action_repo }} 17 | ref: ${{ env.action_ref }} 18 | path: _shared-workflows-dockerhub-login 19 | persist-credentials: false 20 | 21 | - name: Get secrets for DockerHub login 22 | id: get-secrets 23 | uses: ./_shared-workflows-dockerhub-login/actions/get-vault-secrets 24 | with: 25 | common_secrets: | 26 | DOCKERHUB_USERNAME=dockerhub:username 27 | DOCKERHUB_PASSWORD=dockerhub:password 28 | 29 | - name: Log in to Docker Hub 30 | uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 31 | with: 32 | username: ${{ env.DOCKERHUB_USERNAME }} 33 | password: ${{ env.DOCKERHUB_PASSWORD }} 34 | -------------------------------------------------------------------------------- /actions/find-pr-for-commit/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [1.0.1](https://github.com/grafana/shared-workflows/compare/find-pr-for-commit-v1.0.0...find-pr-for-commit/v1.0.1) (2025-06-04) 4 | 5 | 6 | ### 📝 Documentation 7 | 8 | * **multiple-actions:** move permissions to job level in workflow examples ([49c90b1](https://github.com/grafana/shared-workflows/commit/49c90b10fcbce463983bed45932cf468b8bd06ce)) 9 | * **multiple-actions:** move permissions to job level in workflows ([#969](https://github.com/grafana/shared-workflows/issues/969)) ([49c90b1](https://github.com/grafana/shared-workflows/commit/49c90b10fcbce463983bed45932cf468b8bd06ce)) 10 | * update all readmes to replace hyphen with slash ([#1008](https://github.com/grafana/shared-workflows/issues/1008)) ([472df76](https://github.com/grafana/shared-workflows/commit/472df76fb1cbb92a17fb9e055bdf0d1399109ee3)) 11 | 12 | 13 | ### 🔧 Miscellaneous Chores 14 | 15 | * **main:** release push-to-gar-docker 0.3.0 ([#794](https://github.com/grafana/shared-workflows/issues/794)) ([a7bc536](https://github.com/grafana/shared-workflows/commit/a7bc5367c4a91c389526d58839d8f6224dba4dcc)) 16 | 17 | ## 1.0.0 (2025-01-29) 18 | 19 | 20 | ### 🎉 Features 21 | 22 | * update readme to include new version change ([#729](https://github.com/grafana/shared-workflows/issues/729)) ([8fe61d1](https://github.com/grafana/shared-workflows/commit/8fe61d10e85dfd9c3d280f5af371603cbf6f8f91)) 23 | -------------------------------------------------------------------------------- /actions/find-pr-for-commit/action.yaml: -------------------------------------------------------------------------------- 1 | name: Find PR for commit 2 | description: Find the PR associated with a commit 3 | 4 | inputs: 5 | owner: 6 | description: The owner of the repository 7 | default: ${{ github.repository_owner }} 8 | required: false 9 | 10 | repo: 11 | description: The repository name 12 | default: ${{ github.event.repository.name }} 13 | required: false 14 | 15 | commitrev: 16 | description: The commit SHA to find the PR for 17 | # If this is a PR, use the PR head SHA. This is because `github.sha` is the 18 | # merge commit SHA which will not have a PR associated with it. The PR head 19 | # SHA is the commit that was pushed to the PR branch. 20 | default: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }} 21 | required: false 22 | 23 | token: 24 | description: | 25 | The GitHub token to use for the query. Must have `contents:read` and 26 | `pull-requests:read` permissions on the target repository. 27 | default: ${{ github.token }} 28 | required: false 29 | 30 | outputs: 31 | pr_number: 32 | description: The PR number associated with the commit 33 | value: ${{ fromjson(steps.find-commit-pr.outputs.data).repository.object.associatedPullRequests.edges[0].node.number }} 34 | 35 | runs: 36 | using: composite 37 | steps: 38 | - id: find-commit-pr 39 | uses: octokit/graphql-action@8ad880e4d437783ea2ab17010324de1075228110 # v2.3.2 40 | with: 41 | query: | 42 | query associatedPRs($commitrev: String, $repo: String!, $owner: String!) { 43 | repository(name: $repo, owner: $owner) { 44 | object(expression: $commitrev) { 45 | ... on Commit { 46 | associatedPullRequests(first: 1, orderBy: {field: UPDATED_AT, direction: DESC}) { 47 | edges { 48 | node { 49 | number 50 | } 51 | } 52 | } 53 | } 54 | } 55 | } 56 | } 57 | variables: | 58 | owner: ${{ inputs.owner }} 59 | repo: ${{ inputs.repo }} 60 | commitrev: ${{ inputs.commitrev }} 61 | env: 62 | GITHUB_TOKEN: ${{ inputs.token }} 63 | -------------------------------------------------------------------------------- /actions/generate-openapi-clients/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [1.0.2](https://github.com/grafana/shared-workflows/compare/generate-openapi-clients-v1.0.1...generate-openapi-clients/v1.0.2) (2025-06-04) 4 | 5 | 6 | ### 🐛 Bug Fixes 7 | 8 | * ensure every action disables git credential persistence ([#821](https://github.com/grafana/shared-workflows/issues/821)) ([31ebf3f](https://github.com/grafana/shared-workflows/commit/31ebf3f8e5d0f8709e6ec4ef73b39dd2bd08f959)) 9 | * **everything:** fix all things for zizmor ([af9b0c5](https://github.com/grafana/shared-workflows/commit/af9b0c52635d39023136fb9312a354f91d9b2bfd)) 10 | 11 | 12 | ### 📝 Documentation 13 | 14 | * **multiple-actions:** move permissions to job level in workflow examples ([49c90b1](https://github.com/grafana/shared-workflows/commit/49c90b10fcbce463983bed45932cf468b8bd06ce)) 15 | * **multiple-actions:** move permissions to job level in workflows ([#969](https://github.com/grafana/shared-workflows/issues/969)) ([49c90b1](https://github.com/grafana/shared-workflows/commit/49c90b10fcbce463983bed45932cf468b8bd06ce)) 16 | * update all readmes to replace hyphen with slash ([#1008](https://github.com/grafana/shared-workflows/issues/1008)) ([472df76](https://github.com/grafana/shared-workflows/commit/472df76fb1cbb92a17fb9e055bdf0d1399109ee3)) 17 | 18 | 19 | ### 🔧 Miscellaneous Chores 20 | 21 | * **deps:** update actions/cache action to v4.2.1 ([#788](https://github.com/grafana/shared-workflows/issues/788)) ([e26a7f2](https://github.com/grafana/shared-workflows/commit/e26a7f265ddef3a68c322a94a716e6453f656cba)) 22 | * **deps:** update actions/cache action to v4.2.2 ([#822](https://github.com/grafana/shared-workflows/issues/822)) ([0c036cd](https://github.com/grafana/shared-workflows/commit/0c036cdbfb4c912c287f0023073c4c07c10a76e7)) 23 | * **deps:** update actions/cache action to v4.2.3 ([#858](https://github.com/grafana/shared-workflows/issues/858)) ([bc9486e](https://github.com/grafana/shared-workflows/commit/bc9486e0e7cbe24b54d0dcdf8be459eb777567b0)) 24 | * **deps:** update stefanzweifel/git-auto-commit-action action to v5.2.0 ([#908](https://github.com/grafana/shared-workflows/issues/908)) ([da511b7](https://github.com/grafana/shared-workflows/commit/da511b720bc646fe01a29ddaf37e92df2c4bacb3)) 25 | * **main:** release push-to-gar-docker 0.3.0 ([#794](https://github.com/grafana/shared-workflows/issues/794)) ([a7bc536](https://github.com/grafana/shared-workflows/commit/a7bc5367c4a91c389526d58839d8f6224dba4dcc)) 26 | 27 | ## [1.0.1](https://github.com/grafana/shared-workflows/compare/generate-openapi-clients-v1.0.0...generate-openapi-clients-v1.0.1) (2025-01-28) 28 | 29 | 30 | ### 🔧 Miscellaneous Chores 31 | 32 | * **deps:** update actions/cache action to v4.2.0 ([#636](https://github.com/grafana/shared-workflows/issues/636)) ([c4422fc](https://github.com/grafana/shared-workflows/commit/c4422fc4a4fa6cddae3862c7df7b4ec5f251053f)) 33 | * **deps:** update stefanzweifel/git-auto-commit-action action to v5.1.0 ([#689](https://github.com/grafana/shared-workflows/issues/689)) ([f690839](https://github.com/grafana/shared-workflows/commit/f6908398758c52211c17db8b0db17241ea521dd1)) 34 | * update readme when a new release is available ([#548](https://github.com/grafana/shared-workflows/issues/548)) ([9bf9163](https://github.com/grafana/shared-workflows/commit/9bf9163126c44247bcee6b6b9390eb488f9ead53)) 35 | 36 | ## 1.0.0 (2024-11-28) 37 | 38 | 39 | ### 🎉 Features 40 | 41 | * modify openapi spec at client generation time ([#204](https://github.com/grafana/shared-workflows/issues/204)) ([fc84de9](https://github.com/grafana/shared-workflows/commit/fc84de984d84586aaa4c05c88620553d1473f735)) 42 | 43 | 44 | ### 🐛 Bug Fixes 45 | 46 | * generate go client in a subdir ([#208](https://github.com/grafana/shared-workflows/issues/208)) ([335e261](https://github.com/grafana/shared-workflows/commit/335e261108a1299ee06227acad2e487118e3110e)) 47 | 48 | 49 | ### 🔧 Miscellaneous Chores 50 | 51 | * **deps:** update actions/cache action to v4.1.0 ([#441](https://github.com/grafana/shared-workflows/issues/441)) ([e583f36](https://github.com/grafana/shared-workflows/commit/e583f3676b58bba1b3a278be432b4220800abf2f)) 52 | * **deps:** update actions/cache action to v4.1.1 ([#448](https://github.com/grafana/shared-workflows/issues/448)) ([db270ac](https://github.com/grafana/shared-workflows/commit/db270ac9e0cd900940a87e7187c1d4863a997568)) 53 | * **deps:** update actions/cache action to v4.1.2 ([#494](https://github.com/grafana/shared-workflows/issues/494)) ([0f7e124](https://github.com/grafana/shared-workflows/commit/0f7e1244ff37782aaca907e8287d73173776646f)) 54 | -------------------------------------------------------------------------------- /actions/generate-openapi-clients/README.md: -------------------------------------------------------------------------------- 1 | # Generate OpenAPI clients 2 | 3 | This action generates clients from an OpenAPI spec. It's meant to generate clients in an uniform way across our organization 4 | 5 | _Note: For now, it only generates Go code. But it's structured in a way that any of the languages supported by the openapi-generator could be supported at the same time._ 6 | 7 | ## Inputs 8 | 9 | | Name | Type | Description | Default Value | Required | 10 | | ------------------ | ------- | --------------------------------------------------------------------------------------------- | ---------------------------- | -------- | 11 | | generator-version | string | The version of the OpenAPI generator to use | "7.7.0" | false | 12 | | spec-path | string | The path to the OpenAPI spec to generate the client from. Supports JSON or YAML | N/A | true | 13 | | output-dir | string | The directory to output the generated client to | "." | false | 14 | | commit-changes | boolean | If true, the action will commit and push the changes to the repository, if there's a diff. | true | false | 15 | | commit-message | string | The commit message to use when committing the changes | "Update clients and publish" | false | 16 | | package-name | string | The name of the package to generate | N/A | true | 17 | | modify-spec-script | string | The path to an executable script that modifies the OpenAPI spec before generating the client. | "" | false | 18 | 19 | ## Example workflow 20 | 21 | 22 | 23 | ```yaml 24 | name: Generate Clients 25 | 26 | on: 27 | push: 28 | branches: 29 | - main 30 | 31 | jobs: 32 | build-and-publish: 33 | runs-on: ubuntu-latest 34 | permissions: 35 | contents: write # Only needed if `commit-changes` is set to true 36 | steps: 37 | - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v1.0.2 38 | with: 39 | persist-credentials: false 40 | 41 | - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v1.0.2 42 | with: 43 | go-version: 1.18 44 | - name: Generate clients 45 | uses: grafana/shared-workflows/actions/generate-openapi-clients@generate-openapi-clients/v1.0.2 46 | with: 47 | package-name: slo 48 | spec-path: openapi.yaml 49 | modify-spec-script: .github/workflows/modify-spec.sh # Optional, see "Spec Modifications" section 50 | ``` 51 | 52 | 53 | 54 | ### Spec Modifications at Runtime 55 | 56 | The `modify-spec-script` attribute is the path to an executable script that modifies the OpenAPI spec before generating the client. 57 | The spec will be piped into the script and the script should output the modified spec to stdout. 58 | 59 | _Note: This is used as a workaround for the OpenAPI generator not supporting certain features. By using 60 | this feature, the spec will be modified temporarily, and the changes will not be committed._ 61 | 62 | Here's an example of a modification script: 63 | 64 | ```bash 65 | #! /usr/bin/env bash 66 | set -euo pipefail 67 | 68 | SCHEMA=`cat` # Read stdin 69 | modify() { 70 | SCHEMA="$(echo "${SCHEMA}" | jq "${1}")" 71 | } 72 | modify '.components.schemas.FormattedApiApiKey.properties.id = { "anyOf": [ { "type": "string" }, { "type": "number" } ] }' 73 | modify '.components.schemas.FormattedApiApiKeyListResponse.properties.items.items.properties.id = { "anyOf": [ { "type": "string" }, { "type": "number" } ] }' 74 | modify '.components.schemas.FormattedOrgMembership.properties.allowGCloudTrial = { "anyOf": [ { "type": "boolean" }, { "type": "number" } ] }' 75 | modify '.components.schemas.FormattedApiOrgPublic.properties.allowGCloudTrial = { "anyOf": [ { "type": "boolean" }, { "type": "number" } ] }' 76 | modify '.paths["/v1/accesspolicies"].get.responses["200"].content["application/json"].schema = { 77 | "type": "object", 78 | "properties": { 79 | "items": { 80 | "type": "array", 81 | "items": { 82 | "$ref": "#/components/schemas/AuthAccessPolicy" 83 | } 84 | } 85 | } 86 | }' 87 | 88 | echo "${SCHEMA}" 89 | ``` 90 | 91 | This script should be saved to a file and its path given in the `modify-spec-script` attribute. 92 | -------------------------------------------------------------------------------- /actions/generate-openapi-clients/action.yaml: -------------------------------------------------------------------------------- 1 | name: Generate OpenAPI client 2 | description: Takes in a locally stored OpenAPI spec and generates a client from it 3 | 4 | inputs: 5 | generator-version: 6 | description: "The version of the OpenAPI generator to use" 7 | required: false 8 | default: "7.7.0" 9 | spec-path: 10 | description: "The path to the OpenAPI spec to generate the client from" 11 | required: true 12 | output-dir: 13 | description: "The directory to output the generated client to" 14 | required: false 15 | default: "." 16 | commit-changes: 17 | description: If true, the action will commit and push the changes to the repository, if there's a diff. 18 | required: false 19 | default: "true" 20 | commit-message: 21 | description: The commit message to use when committing the changes 22 | required: false 23 | default: "Update clients and publish" 24 | package-name: 25 | description: The name of the package to generate 26 | required: true 27 | modify-spec-script: 28 | description: | 29 | The path to an executable script that modifies the OpenAPI spec before generating the client. 30 | The spec will be piped into the script and the script should output the modified spec to stdout. 31 | Note: This is used as a workaround for the OpenAPI generator not supporting certain features. By using 32 | this feature, the spec will be modified temporarily, and the changes will not be committed. 33 | required: false 34 | default: "" 35 | 36 | runs: 37 | using: composite 38 | steps: 39 | # Get openapi-generator 40 | - id: openapi-generator-cache 41 | uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 42 | with: 43 | key: openapi-generator-${{ inputs.generator-version }} 44 | path: openapi-generator-cli.jar 45 | 46 | - name: Download openapi-generator 47 | shell: bash 48 | if: steps.openapi-generator-cache.outputs.cache-hit != 'true' 49 | env: 50 | GENERATOR_VERSION: ${{ inputs.generator-version }} 51 | run: | 52 | wget -nv "https://repo1.maven.org/maven2/org/openapitools/openapi-generator-cli/${GENERATOR_VERSION}/openapi-generator-cli-${GENERATOR_VERSION}.jar" -O ./openapi-generator-cli.jar 53 | - uses: actions/cache/save@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 54 | if: steps.openapi-generator-cache.outputs.cache-hit != 'true' 55 | with: 56 | key: openapi-generator-${{ inputs.generator-version }} 57 | path: openapi-generator-cli.jar 58 | 59 | # Modify the spec if a script is provided 60 | - name: Modify spec 61 | id: modify-spec 62 | shell: bash 63 | env: 64 | MODIFY_SCRIPT: ${{ inputs.modify-spec-script }} 65 | SPEC_PATH: ${{ inputs.spec-path }} 66 | run: | 67 | if [ -n "${MODIFY_SCRIPT}" ]; then 68 | cat "${SPEC_PATH}" | "${MODIFY_SCRIPT}" > temp-spec.txt 69 | echo "spec-path=temp-spec.txt" | tee -a "${GITHUB_OUTPUT}" 70 | else 71 | echo "spec-path=${SPEC_PATH}" | tee -a "${GITHUB_OUTPUT}" 72 | fi 73 | 74 | # Generate the client 75 | - shell: bash 76 | run: ${GITHUB_ACTION_PATH}/generate.sh 77 | env: 78 | OUTPUT_DIR: ${{ inputs.output-dir }} 79 | PACKAGE_NAME: ${{ inputs.package-name }} 80 | SPEC_PATH: ${{ steps.modify-spec.outputs.spec-path }} 81 | 82 | # Cleanup files that shouldn't be committed 83 | - name: Cleanup 84 | shell: bash 85 | env: 86 | MODIFY_SCRIPT: ${{ inputs.modify-spec-script }} 87 | run: | 88 | rm openapi-generator-cli.jar 89 | 90 | if [ -n "${MODIFY_SCRIPT}" ]; then 91 | rm temp-spec.txt 92 | fi 93 | 94 | # Commit the changes 95 | - uses: stefanzweifel/git-auto-commit-action@b863ae1933cb653a53c021fe36dbb774e1fb9403 # v5.2.0 96 | if: ${{ inputs.commit-changes == 'true' }} 97 | with: 98 | commit_message: ${{ inputs.commit-message }} 99 | -------------------------------------------------------------------------------- /actions/generate-openapi-clients/generate.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | set -euo pipefail 3 | 4 | # Generate Go client (TODO: Add support for other languages) 5 | GO_DIR="${OUTPUT_DIR}/go/${PACKAGE_NAME}" 6 | rm -rf "${GO_DIR}" 7 | java -jar openapi-generator-cli.jar generate \ 8 | -i "${SPEC_PATH}" \ 9 | -g go \ 10 | -o "${GO_DIR}" \ 11 | --git-user-id "grafana" \ 12 | --git-repo-id "${REPO_NAME}/go" \ 13 | --package-name "${PACKAGE_NAME}" \ 14 | -p isGoSubmodule=true \ 15 | -p disallowAdditionalPropertiesIfNotPresent=false \ 16 | -t "${GITHUB_ACTION_PATH}/templates/go" 17 | 18 | pushd "${GO_DIR}" && go mod tidy && popd 19 | if ! command -v goimports &> /dev/null 20 | then 21 | go install golang.org/x/tools/cmd/goimports@latest 22 | fi 23 | find "${GO_DIR}" -name \*.go -exec goimports -w {} \; 24 | 25 | -------------------------------------------------------------------------------- /actions/get-latest-workflow-artifact/.bun-version: -------------------------------------------------------------------------------- 1 | 1.2.13 2 | -------------------------------------------------------------------------------- /actions/get-latest-workflow-artifact/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /actions/get-latest-workflow-artifact/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 0.1.0 (2025-06-04) 4 | 5 | 6 | ### 🎉 Features 7 | 8 | * new get-latest-workflow-artifact action ([#988](https://github.com/grafana/shared-workflows/issues/988)) ([9a36195](https://github.com/grafana/shared-workflows/commit/9a361957d23c19436a06ae796cbf47de1e15eb67)) 9 | 10 | 11 | ### 🔧 Miscellaneous Chores 12 | 13 | * **main:** release push-to-gar-docker 0.3.0 ([#794](https://github.com/grafana/shared-workflows/issues/794)) ([a7bc536](https://github.com/grafana/shared-workflows/commit/a7bc5367c4a91c389526d58839d8f6224dba4dcc)) 14 | -------------------------------------------------------------------------------- /actions/get-latest-workflow-artifact/README.md: -------------------------------------------------------------------------------- 1 | # get-latest-workflow-artifact 2 | 3 | This action can be used to download the latest artifact of a specific workflow within the context of a pull request. 4 | One use-case for this is to access a report generated by another workflow. 5 | 6 | Required permissions: 7 | 8 | - `pull-requests: read` 9 | - `actions: read` 10 | 11 | | Input | Description | Required | Default | 12 | | --------------- | ---------------------------------- | -------- | ----------------------------------------- | 13 | | `workflow-id` | ID or filename of the workflow | yes | | 14 | | `artifact-name` | Name of the artifact to download | yes | | 15 | | `repository` | Owner/Name | no | `${{ github.repository }}` | 16 | | `pr-number` | Number of the PR to consider | no | `${{ github.event.pull_request.number }}` | 17 | | `path` | Directory to store the artifact in | no | `${{ github.workspace }}` | 18 | | `github-token` | GitHub token | no | `${{ github.token }}` | 19 | 20 | | Output | Description | 21 | | ------------------------ | -------------------------------------- | 22 | | `artifact-download-path` | Path where the artifact was downloaded | 23 | | `artifact-id` | ID of the artifact that was downloaded | 24 | | `workflow-run-id` | ID of the Workflow Run | 25 | -------------------------------------------------------------------------------- /actions/get-latest-workflow-artifact/action.yml: -------------------------------------------------------------------------------- 1 | name: get-latest-workflow-artifact 2 | description: Retrieve a specific artifact of the latest run of a workflow for a pull request 3 | inputs: 4 | artifact-name: 5 | description: Name of a specific artifact 6 | required: true 7 | workflow-id: 8 | description: ID of the workflow inside the current repository 9 | required: true 10 | repository: 11 | description: Repository of the target workflow (e.g. `grafana/grafana`) 12 | required: false 13 | default: ${{ github.repository }} 14 | pr-number: 15 | description: Pull request the workflow run is associated with 16 | required: false 17 | default: ${{ github.event.pull_request.number }} 18 | github-token: 19 | description: GitHub token to access the workflow and artifact 20 | required: false 21 | default: ${{ github.token }} 22 | path: 23 | description: Destination path 24 | required: false 25 | default: ${{ github.workspace }} 26 | 27 | outputs: 28 | artifact-download-path: 29 | description: Path of the downloaded artifact 30 | value: ${{ steps.get-artifact.outputs.artifact-download-path }} 31 | artifact-id: 32 | description: ID of the downloaded artifact 33 | value: ${{ steps.get-artifact.outputs.artifact-id }} 34 | workflow-run-id: 35 | description: ID of the considered workflow run 36 | value: ${{ steps.get-artifact.outputs.workflow-run-id }} 37 | 38 | runs: 39 | using: "composite" 40 | steps: 41 | - name: Install bun package manager 42 | uses: oven-sh/setup-bun@4bc047ad259df6fc24a6c9b0f9a0cb08cf17fbe5 # v2.0.1 43 | with: 44 | bun-version-file: ${{ github.action_path }}/.bun-version 45 | 46 | - name: Install dependencies 47 | shell: bash 48 | working-directory: ${{ github.action_path }} 49 | run: | 50 | bun install --frozen-lockfile --production 51 | 52 | - name: Get latest workflow artifact 53 | id: get-artifact 54 | shell: bash 55 | working-directory: ${{ github.action_path }} 56 | env: 57 | INPUT_GITHUB-TOKEN: ${{ inputs.github-token }} 58 | INPUT_ARTIFACT-NAME: ${{ inputs.artifact-name }} 59 | INPUT_WORKFLOW-ID: ${{ inputs.workflow-id }} 60 | INPUT_REPOSITORY: ${{ inputs.repository }} 61 | INPUT_PR-NUMBER: ${{ inputs.pr-number }} 62 | INPUT_PATH: ${{ inputs.path }} 63 | NODE_ENV: "production" 64 | run: | 65 | bun run src/main.ts 66 | -------------------------------------------------------------------------------- /actions/get-latest-workflow-artifact/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "get-latest-workflow-artifact-action", 3 | "version": "1.0.0", 4 | "author": "", 5 | "repository": { 6 | "type": "git", 7 | "url": "git+https://github.com/grafana/get-latest-workflow-artifact-action.git" 8 | }, 9 | "main": "dist/main.js", 10 | "dependencies": { 11 | "@actions/artifact": "^2.3.2", 12 | "@actions/core": "^1.11.1", 13 | "@actions/github": "^6.0.1" 14 | }, 15 | "devDependencies": { 16 | "@types/bun": "latest", 17 | "@types/node": "^22.15.18" 18 | }, 19 | "bugs": { 20 | "url": "https://github.com/grafana/get-latest-workflow-artifact-action/issues" 21 | }, 22 | "description": "", 23 | "homepage": "https://github.com/grafana/get-latest-workflow-artifact-action#readme", 24 | "license": "ISC", 25 | "private": true, 26 | "scripts": {} 27 | } 28 | -------------------------------------------------------------------------------- /actions/get-latest-workflow-artifact/src/main.ts: -------------------------------------------------------------------------------- 1 | import * as core from "@actions/core"; 2 | import * as github from "@actions/github"; 3 | import { DefaultArtifactClient } from "@actions/artifact"; 4 | import * as filepath from "node:path"; 5 | 6 | async function main() { 7 | const ghToken = core.getInput("github-token", { required: true }); 8 | const workflowId = core.getInput("workflow-id", { required: true }); 9 | const [repoOwner, repoName] = core 10 | .getInput("repository", { required: true }) 11 | .split("/"); 12 | const prNumber = parseInt(core.getInput("pr-number", { required: true }), 10); 13 | const artifactName = core.getInput("artifact-name", { required: true }); 14 | let path = core.getInput("path", { required: false }); 15 | 16 | if (!path) { 17 | const workspace = process.env.GITHUB_WORKSPACE || process.cwd(); 18 | if (!workspace) { 19 | throw new Error("GITHUB_WORKSPACE is not set"); 20 | } 21 | path = workspace; 22 | } 23 | 24 | path = filepath.join(path, artifactName); 25 | 26 | const client = github.getOctokit(ghToken); 27 | 28 | const { data } = await client.rest.pulls.get({ 29 | owner: repoOwner, 30 | repo: repoName, 31 | pull_number: prNumber, 32 | }); 33 | 34 | const headSha = data.head.sha; 35 | // Now let's get all workflows associated with this sha. 36 | const { data: runs } = await client.rest.actions.listWorkflowRuns({ 37 | repo: repoName, 38 | owner: repoOwner, 39 | head_sha: headSha, 40 | workflow_id: workflowId, 41 | status: "completed", 42 | }); 43 | 44 | if (runs.workflow_runs.length <= 0) { 45 | throw new Error(`No workflow runs found for sha ${headSha}`); 46 | } 47 | 48 | const latestRun = runs.workflow_runs[0]; 49 | core.info(`Latest run: ${latestRun.id} <${latestRun.html_url}>`); 50 | 51 | // Now that we have the run we can get a list of all artifacts there: 52 | const { data: artifacts } = 53 | await client.rest.actions.listWorkflowRunArtifacts({ 54 | owner: repoOwner, 55 | repo: repoName, 56 | run_id: latestRun.id, 57 | }); 58 | 59 | const artifact = new DefaultArtifactClient(); 60 | const candidates = artifacts.artifacts.filter( 61 | (artifact) => artifact.name == artifactName, 62 | ); 63 | if (candidates.length <= 0) { 64 | throw new Error(`No artifacts found with name ${artifactName}`); 65 | } 66 | 67 | const response = await artifact.downloadArtifact(candidates[0].id, { 68 | path: path, 69 | findBy: { 70 | repositoryName: repoName, 71 | repositoryOwner: repoOwner, 72 | workflowRunId: latestRun.id, 73 | token: ghToken, 74 | }, 75 | }); 76 | core.setOutput("artifact-download-path", response.downloadPath); 77 | core.setOutput("artifact-id", candidates[0].id); 78 | core.setOutput("workflow-run-id", latestRun.id); 79 | } 80 | 81 | main(); 82 | -------------------------------------------------------------------------------- /actions/get-vault-secrets/README.md: -------------------------------------------------------------------------------- 1 | # get-vault-secrets 2 | 3 | > [!NOTE] 4 | > If you are at Grafana Labs, follow these steps in the [internal documentation](https://enghub.grafana-ops.net/docs/default/component/deployment-tools/platform/continuous-integration/#vault-storing-your-secrets) for Vault instructions and best practices. 5 | 6 | From a `grafana/` org repository, get a secret from the Grafana vault instance. 7 | The secret format is defined here: 8 | 9 | ## Examples 10 | 11 | ### Using Environment Variables (default) 12 | 13 | 14 | 15 | ```yaml 16 | name: CI 17 | on: 18 | pull_request: 19 | 20 | jobs: 21 | build: 22 | runs-on: ubuntu-latest 23 | 24 | # These permissions are needed to assume roles from Github's OIDC. 25 | permissions: 26 | contents: read 27 | id-token: write 28 | 29 | steps: 30 | - id: get-secrets 31 | uses: grafana/shared-workflows/actions/get-vault-secrets@get-vault-secrets/v1.2.1 32 | with: 33 | # Secrets placed in the ci/common/ path in Vault 34 | common_secrets: | 35 | ENVVAR1=test-secret:testing 36 | # Secrets placed in the ci/repo/grafana// path in Vault 37 | repo_secrets: | 38 | ENVVAR2=test-secret:key1 39 | 40 | # Use the secrets 41 | # You can use the envvars directly in scripts 42 | - name: echo 43 | run: | 44 | echo "$ENVVAR1" 45 | echo "${ENVVAR2}" 46 | ``` 47 | 48 | 49 | 50 | ### Using Outputs 51 | 52 | You can also use the action with `export_env: false` to get secrets as outputs instead of environment variables: 53 | 54 | 55 | 56 | ```yaml 57 | name: CI 58 | on: 59 | pull_request: 60 | 61 | # These permissions are needed to assume roles from Github's OIDC. 62 | permissions: 63 | contents: read 64 | id-token: write 65 | 66 | jobs: 67 | build: 68 | runs-on: ubuntu-latest 69 | 70 | steps: 71 | - id: get-secrets 72 | uses: grafana/shared-workflows/actions/get-vault-secrets@get-vault-secrets/v1.2.1 73 | with: 74 | # Secrets placed in the ci/common/ path in Vault 75 | common_secrets: | 76 | SECRET1=test-secret:testing 77 | # Secrets placed in the ci/repo/grafana// path in Vault 78 | repo_secrets: | 79 | SECRET2=test-secret:key1 80 | # Set to false to get secrets as outputs instead of environment variables 81 | export_env: false 82 | 83 | # Use the secrets from the JSON output in the env block 84 | - name: echo 85 | env: 86 | ENVVAR1: ${{ fromJSON(steps.get-secrets.outputs.secrets).SECRET1 }} 87 | ENVVAR2: ${{ fromJSON(steps.get-secrets.outputs.secrets).SECRET2 }} 88 | run: | 89 | echo "$ENVVAR1" 90 | echo "${ENVVAR2}" 91 | ``` 92 | 93 | 94 | 95 | This approach is useful when you need to pass secrets to other actions or reusable workflows as inputs, while keeping them secure. It's also beneficial when you want to limit which steps have access to the secrets, as environment variables are available to all subsequent steps in a job, whereas outputs require explicit passing to each step that needs them. 96 | -------------------------------------------------------------------------------- /actions/get-vault-secrets/action.yaml: -------------------------------------------------------------------------------- 1 | name: Get Vault Secrets 2 | description: Composite action (step) to get secrets from Grafana Labs' Vault instance. 3 | inputs: 4 | repo_secrets: 5 | description: | 6 | Repository-specific secret mapping. Only Grafana Labs employees can list these secrets in Vault. 7 | These secrets are stored in the `ci/data/repo/grafana//` path in Vault. 8 | Ex: 9 | ``` 10 | repo_secrets: | 11 | ENVVAR1=secretpath:key 12 | ENVVAR2=secretpath:key2 13 | ``` 14 | common_secrets: 15 | description: | 16 | Common secrets mapping. Only Grafana Labs employees can list these secrets in Vault. 17 | These secrets are stored in the `ci/data/common/` path in Vault. 18 | Ex: 19 | ``` 20 | repo_secrets: | 21 | ENVVAR1=secretpath:key 22 | ENVVAR2=secretpath:key2 23 | ``` 24 | 25 | vault_instance: 26 | description: | 27 | The Vault instance to use (`dev` or `ops`). Defaults to `ops`. 28 | default: ops 29 | 30 | export_env: 31 | description: | 32 | Whether to export secrets as environment variables, making them available to all subsequent steps. Defaults to `true`. 33 | default: "true" 34 | 35 | outputs: 36 | secrets: 37 | description: "JSON object containing all the secrets" 38 | value: ${{ toJSON(steps.import-secrets.outputs) }} 39 | 40 | runs: 41 | using: composite 42 | steps: 43 | - id: check-vault-instance 44 | if: inputs.vault_instance != 'dev' && inputs.vault_instance != 'ops' 45 | shell: sh 46 | env: 47 | VAULT_INSTANCE: ${{ inputs.vault_instance }} 48 | run: | 49 | echo "Invalid value for vault_instance input: ${VAULT_INSTANCE}. Must be 'dev' or 'ops'." 50 | exit 1 51 | 52 | # Translate the secrets into a format that the Vault action can understand 53 | - id: translate-secrets 54 | shell: bash 55 | run: "${GITHUB_ACTION_PATH}/translate-secrets.bash" 56 | env: 57 | REPO_SECRETS: ${{ inputs.repo_secrets }} 58 | COMMON_SECRETS: ${{ inputs.common_secrets }} 59 | REPO: ${{ github.repository }} 60 | 61 | - id: get-github-jwt-token 62 | uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 63 | env: 64 | VAULT_INSTANCE: ${{ inputs.vault_instance }} 65 | with: 66 | script: | 67 | const jwt = await core.getIDToken(`vault-github-actions-grafana-${process.env.VAULT_INSTANCE}`); 68 | core.setSecret(jwt); 69 | core.setOutput("github-jwt",jwt); 70 | 71 | # Get the secrets 72 | - name: Import Secrets 73 | id: import-secrets 74 | uses: hashicorp/vault-action@7709c609789c5e27b757a85817483caadbb5939a # v3.3.0 75 | with: 76 | url: "https://vault-github-actions.grafana-${{ inputs.vault_instance }}.net/" 77 | role: vault-github-actions 78 | path: github-actions-oidc 79 | method: jwt 80 | jwtGithubAudience: "https://vault-github-actions.grafana-${{ inputs.vault_instance }}.net" 81 | extraHeaders: | 82 | Proxy-Authorization-Token: Bearer ${{ steps.get-github-jwt-token.outputs.github-jwt }} 83 | secrets: | 84 | ${{ steps.translate-secrets.outputs.secrets }} 85 | exportEnv: ${{ inputs.export_env }} 86 | -------------------------------------------------------------------------------- /actions/get-vault-secrets/translate-secrets.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Input env: 4 | # - REPO => Repository name 5 | # - COMMON_SECRETS => Common secrets (in the ci/data/common/ vault path): {{ Env Variable Name }}={{ Secret Path }}:{{ Secret Key }} 6 | # - REPO_SECRETS => Repo secrets (in the ci/data/repo/${REPO}/ vault path): {{ Env Variable Name }}={{ Secret Path }}:{{ Secret Key }} 7 | # Output format: "{{ Secret Path }} {{ Secret Key }} | {{ Env Variable Name }}" in the $GITHUB_OUTPUT file 8 | 9 | 10 | # Check if the REPO environment variable is set 11 | if [ -z "$REPO" ]; then 12 | echo "Error: REPO environment variable is not set." 13 | exit 1 14 | fi 15 | 16 | # Check if the GITHUB_OUTPUT environment variable is set. It should be set by Github Actions. 17 | if [ -z "$GITHUB_OUTPUT" ]; then 18 | echo "Error: GITHUB_OUTPUT environment variable is not set." 19 | exit 1 20 | fi 21 | 22 | readonly COMMON_SECRETS GITHUB_OUTPUT REPO REPO_SECRETS 23 | 24 | RESULT="" 25 | 26 | # Function to split a string into parts 27 | split_string() { 28 | local input_string="$1" 29 | IFS='=' read -ra parts <<< "$input_string" 30 | 31 | if [ "${#parts[@]}" -eq 2 ]; then 32 | env_variable_name="${parts[0]}" 33 | secret_parts="${parts[1]}" 34 | 35 | IFS=':' read -ra secret_parts <<< "$secret_parts" 36 | 37 | if [ "${#secret_parts[@]}" -eq 2 ]; then 38 | secret_path="${secret_parts[0]}" 39 | secret_key="${secret_parts[1]}" 40 | fi 41 | fi 42 | } 43 | 44 | # Translate the common secrets 45 | if [ -n "$COMMON_SECRETS" ]; then 46 | for common_secret in $COMMON_SECRETS; do 47 | split_string "$common_secret" 48 | RESULT="${RESULT}ci/data/common/$secret_path $secret_key | $env_variable_name;\n" 49 | done 50 | fi 51 | 52 | # Translate the repo secrets 53 | if [ -n "$REPO_SECRETS" ]; then 54 | for repo_secret in $REPO_SECRETS; do 55 | split_string "$repo_secret" 56 | RESULT="${RESULT}ci/data/repo/$REPO/$secret_path $secret_key | $env_variable_name;\n" 57 | done 58 | fi 59 | 60 | readonly RESULT 61 | 62 | # Print the contents of the output file 63 | echo -e "Secrets that will be queried from Vault:\n$RESULT" 64 | echo -e "secrets< "$GITHUB_OUTPUT" 65 | -------------------------------------------------------------------------------- /actions/get-vault-secrets/translate-secrets.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | # Set up test environment 4 | setup() { 5 | export REPO="grafana/myrepo" 6 | export GITHUB_OUTPUT="secrets_output.txt" 7 | export COMMON_SECRETS="SECRET1=secret1:key1 8 | SECRET2=subfolder/secret2:key2" 9 | export REPO_SECRETS="SECRET3=secret3:key3 10 | SECRET4=subfolder/secret4:key4 11 | " 12 | } 13 | 14 | # Clean up temporary files after tests 15 | teardown() { 16 | rm -f "$GITHUB_OUTPUT" 17 | } 18 | 19 | @test "Check if REPO environment variable is set" { 20 | export REPO= 21 | run ./translate-secrets.bash 22 | [ "$status" -ne 0 ] 23 | [ "${lines[0]}" = "Error: REPO environment variable is not set." ] 24 | } 25 | 26 | @test "Check if GITHUB_OUTPUT environment variable is set" { 27 | export GITHUB_OUTPUT= 28 | run ./translate-secrets.bash 29 | [ "$status" -ne 0 ] 30 | [ "${lines[0]}" = "Error: GITHUB_OUTPUT environment variable is not set." ] 31 | } 32 | 33 | @test "Translate secrets" { 34 | run ./translate-secrets.bash 35 | echo "$output" >&3 36 | [ "$status" -eq 0 ] 37 | [ "$output" = "Secrets that will be queried from Vault: 38 | ci/data/common/secret1 key1 | SECRET1; 39 | ci/data/common/subfolder/secret2 key2 | SECRET2; 40 | ci/data/repo/grafana/myrepo/secret3 key3 | SECRET3; 41 | ci/data/repo/grafana/myrepo/subfolder/secret4 key4 | SECRET4;" ] 42 | 43 | echo -e "\nGITHUB_OUTPUT:\n$(cat "$GITHUB_OUTPUT")" >&3 44 | [ "$(cat "$GITHUB_OUTPUT")" = "secrets< 73 | 74 | ```yml 75 | name: Lint PR title 76 | 77 | on: 78 | pull_request: 79 | types: [opened, edited, synchronize] 80 | merge_group: 81 | types: [checks_requested] 82 | jobs: 83 | lint-pr-title: 84 | runs-on: ubuntu-latest 85 | steps: 86 | - uses: actions/checkout@v4 87 | with: 88 | persist-credentials: false 89 | 90 | - id: lint-pr-title 91 | uses: grafana/shared-workflows/actions/lint-pr-title@lint-pr-title/v1.2.0 92 | with: 93 | config-path: "${{ github.workspace }}/commitlint.config.js" 94 | title-only: false 95 | ``` 96 | 97 | ## Example without config path: 98 | 99 | ```yml 100 | name: Lint PR title 101 | 102 | on: 103 | pull_request: 104 | types: [opened, edited, synchronize] 105 | jobs: 106 | lint-pr-title: 107 | runs-on: ubuntu-latest 108 | steps: 109 | - id: lint-pr-title 110 | uses: grafana/shared-workflows/actions/lint-pr-title@lint-pr-title/v1.2.0 111 | ``` 112 | 113 | 114 | -------------------------------------------------------------------------------- /actions/lint-pr-title/action.yml: -------------------------------------------------------------------------------- 1 | name: Lint pull request title using Javascript 2 | description: Run lint on the PR title to check if It matches the commitlint specification. 3 | 4 | inputs: 5 | config-path: 6 | default: "./commitlint.config.js" 7 | description: "Path to the commitlint configuration file, relative to the action's directory." 8 | required: false 9 | 10 | title-only: 11 | default: "true" 12 | description: "Check only the PR/commit title. If false, it will check the whole PR/commit message." 13 | required: false 14 | 15 | runs: 16 | using: "composite" 17 | steps: 18 | - name: Install bun package manager 19 | uses: oven-sh/setup-bun@735343b667d3e6f658f44d0eca948eb6282f2b76 # v2.0.2 20 | with: 21 | bun-version-file: actions/lint-pr-title/.bun-version 22 | 23 | - name: Install dependencies 24 | shell: sh 25 | working-directory: ${{ github.action_path }} 26 | run: | 27 | bun install --frozen-lockfile --production 28 | 29 | - name: Lint PR title 30 | shell: sh 31 | working-directory: ${{ github.action_path }} 32 | env: 33 | GITHUB_TOKEN: ${{ github.token }} 34 | INPUT_CONFIG_PATH: ${{ inputs.config-path }} 35 | INPUT_TITLE_ONLY: ${{ inputs.title-only }} 36 | NODE_ENV: "production" 37 | run: | 38 | bun run src/index.ts 39 | 40 | branding: 41 | icon: "shield" 42 | color: "green" 43 | -------------------------------------------------------------------------------- /actions/lint-pr-title/commitlint.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | extends: ["@commitlint/config-conventional"], 3 | rules: { 4 | "body-leading-blank": [1, "always"], 5 | "body-max-line-length": [2, "always", 100], 6 | "footer-leading-blank": [1, "always"], 7 | "footer-max-line-length": [2, "always", 100], 8 | "header-max-length": [2, "always", 100], 9 | "subject-case": [ 10 | 2, 11 | "never", 12 | ["sentence-case", "start-case", "pascal-case", "upper-case"], 13 | ], 14 | "subject-empty": [2, "never"], 15 | "subject-full-stop": [2, "never", "."], 16 | "type-case": [2, "always", "lower-case"], 17 | "type-empty": [2, "never"], 18 | "type-enum": [ 19 | 2, 20 | "always", 21 | [ 22 | "build", 23 | "chore", 24 | "ci", 25 | "docs", 26 | "feat", 27 | "fix", 28 | "perf", 29 | "refactor", 30 | "revert", 31 | "style", 32 | "test", 33 | ], 34 | ], 35 | }, 36 | }; 37 | -------------------------------------------------------------------------------- /actions/lint-pr-title/eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import eslint from "@eslint/js"; 2 | import eslintPluginJest from "eslint-plugin-jest"; 3 | import eslintPluginPrettierRecommended from "eslint-plugin-prettier/recommended"; 4 | import js from "@eslint/js"; 5 | import tseslint from "typescript-eslint"; 6 | 7 | export default tseslint.config( 8 | js.configs.recommended, 9 | eslint.configs.recommended, 10 | ...tseslint.configs.strictTypeChecked, 11 | eslintPluginPrettierRecommended, 12 | { 13 | // Allow unused vars if they start with an underscore 14 | rules: { 15 | "@typescript-eslint/no-unused-vars": [ 16 | "error", 17 | { 18 | varsIgnorePattern: "^_", 19 | argsIgnorePattern: "^_", 20 | }, 21 | ], 22 | }, 23 | languageOptions: { 24 | parserOptions: { 25 | projectService: true, 26 | }, 27 | }, 28 | }, 29 | { 30 | files: ["**/*.js", "**/*.mjs"], 31 | ...tseslint.configs.disableTypeChecked, 32 | }, 33 | { 34 | files: ["test/**/*.ts"], 35 | ...eslintPluginJest.configs["flat/recommended"], 36 | }, 37 | { 38 | ignores: ["coverage/", "dist/", "node_modules/"], 39 | }, 40 | ); 41 | -------------------------------------------------------------------------------- /actions/lint-pr-title/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lint-pr-title", 3 | "version": "0.0.1", 4 | "description": "Ensure your PR title matches the commit lint specification.", 5 | "type": "module", 6 | "exports": { 7 | ".": "./dist/index.js" 8 | }, 9 | "private": true, 10 | "scripts": { 11 | "typecheck": "tsc --noEmit", 12 | "lint": "eslint .", 13 | "test": "bun test" 14 | }, 15 | "keywords": [ 16 | "lint-pr-title", 17 | "github-action", 18 | "commitlint" 19 | ], 20 | "author": "", 21 | "license": "ISC", 22 | "dependencies": { 23 | "@actions/core": "1.11.1", 24 | "@actions/github": "6.0.0", 25 | "@commitlint/config-conventional": "19.8.0", 26 | "@commitlint/format": "19.8.0", 27 | "@commitlint/lint": "19.8.0", 28 | "@commitlint/load": "19.8.0", 29 | "@octokit/core": "6.1.5", 30 | "@octokit/graphql": "8.2.2", 31 | "tmp": "0.2.3" 32 | }, 33 | "devDependencies": { 34 | "@commitlint/types": "19.8.0", 35 | "@eslint/js": "9.25.1", 36 | "@octokit/types": "14.0.0", 37 | "@octokit/webhooks-types": "7.6.1", 38 | "@types/bun": "1.2.11", 39 | "@types/eslint__js": "9.14.0", 40 | "@types/tmp": "0.2.6", 41 | "eslint": "9.25.1", 42 | "eslint-config-prettier": "10.1.2", 43 | "eslint-plugin-jest": "28.11.0", 44 | "eslint-plugin-prettier": "5.2.6", 45 | "prettier": "3.5.3", 46 | "typescript": "5.8.3", 47 | "typescript-eslint": "8.31.1" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /actions/lint-pr-title/src/index.test.ts: -------------------------------------------------------------------------------- 1 | import * as mainModule from "./main"; 2 | 3 | import { 4 | afterEach, 5 | beforeAll, 6 | describe, 7 | expect, 8 | it, 9 | mock, 10 | spyOn, 11 | } from "bun:test"; 12 | 13 | import { WrongEventTypeError } from "./main"; 14 | import { run } from "."; 15 | 16 | async function setEventType(eventType: string) { 17 | await mock.module("@actions/github", () => ({ 18 | context: { 19 | eventName: eventType, 20 | }, 21 | })); 22 | } 23 | 24 | /** 25 | * Tests the "external" interface, the parts which rely on the environment - by 26 | * setting env vars and inputs. 27 | */ 28 | describe("lint", () => { 29 | beforeAll(() => { 30 | process.env.GITHUB_TOKEN = "token"; 31 | }); 32 | 33 | afterEach(() => { 34 | mock.restore(); 35 | }); 36 | 37 | it("rejects unknown event types", async () => { 38 | await setEventType("unknown"); 39 | 40 | expect(run()).rejects.toThrow(WrongEventTypeError); 41 | }); 42 | 43 | it("loads the specified config file", async () => { 44 | await mock.module("@actions/core", () => ({ 45 | getInput: () => "/my-config.js", 46 | })); 47 | 48 | await mock.module("fs/promises", () => ({ 49 | access: () => {}, 50 | })); 51 | 52 | const spy = spyOn(mainModule, "loadConfig"); 53 | 54 | expect(run()).rejects.toThrow(); 55 | 56 | expect(spy).toHaveBeenCalledWith("/my-config.js"); 57 | }); 58 | }); 59 | -------------------------------------------------------------------------------- /actions/lint-pr-title/src/index.ts: -------------------------------------------------------------------------------- 1 | import { LintError, LintResult, handleEvent, loadConfig } from "./main"; 2 | import { access, constants } from "fs/promises"; 3 | import { context, getOctokit } from "@actions/github"; 4 | import { getInput, setFailed } from "@actions/core"; 5 | 6 | import { resolve } from "path"; 7 | 8 | /** 9 | * All code to interact with the environment is in this file. 10 | */ 11 | 12 | /** 13 | * Run the action. The action runs in the context of a GitHub event and will 14 | * load a configuration file and then lint the commit or PR title against the 15 | * provided rules. 16 | * 17 | * @throws If the configuration file is not found or not readable, or if the 18 | * commit or PR title is invalid. 19 | */ 20 | export async function run(): Promise { 21 | const configPath = resolve(getInput("config_path") || "commitlint.config.js"); 22 | const titleOnly = getInput("title_only") === "true"; 23 | 24 | const gitHubToken = process.env.GITHUB_TOKEN; 25 | if (gitHubToken === undefined) { 26 | throw new Error("GITHUB_TOKEN is required."); 27 | } 28 | 29 | const actionConfig = { 30 | configPath, 31 | titleOnly, 32 | }; 33 | 34 | // Throws an error if the config is invalid 35 | try { 36 | await access(configPath, constants.R_OK); 37 | } catch { 38 | throw new Error(`Config file ${configPath} not found or not readable`); 39 | } 40 | console.log(`Loading config from ${configPath}`); 41 | const commitLintConfig = await loadConfig(configPath); 42 | 43 | console.log(`Will lint ${titleOnly ? "titles only" : "titles and bodies"}`); 44 | 45 | return handleEvent(context, getOctokit(gitHubToken), { 46 | actionConfig, 47 | commitLintConfig, 48 | }); 49 | } 50 | 51 | export async function main() { 52 | try { 53 | const result = await run(); 54 | if (!result.valid) { 55 | throw new LintError(result); 56 | } 57 | } catch (error) { 58 | if (error instanceof Error) { 59 | setFailed(error.message); 60 | return; 61 | } 62 | throw error; 63 | } 64 | } 65 | 66 | if (import.meta.main) { 67 | await main(); 68 | } 69 | -------------------------------------------------------------------------------- /actions/lint-pr-title/src/tempfile.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, it } from "bun:test"; 2 | import { tmpFileAsync } from "./tempfile"; 3 | import { readFile } from "node:fs/promises"; 4 | import { existsSync } from "node:fs"; 5 | import { basename, dirname } from "node:path"; 6 | import type { FileOptions } from "tmp"; 7 | 8 | describe("tmpFileAsync", () => { 9 | it.each<{ description: string; options: FileOptions }>([ 10 | { description: "with default options", options: {} }, 11 | { description: "with custom prefix", options: { prefix: "test-" } }, 12 | { description: "with custom postfix", options: { postfix: ".txt" } }, 13 | { description: "with custom directory", options: { tmpdir: "/tmp" } }, 14 | ])( 15 | "should create and cleanup temp file $description", 16 | async ({ options }) => { 17 | let name: string | undefined; 18 | 19 | { 20 | await using tmp = await tmpFileAsync(options); 21 | 22 | name = tmp.name; 23 | const handle = tmp.handle; 24 | 25 | expect(existsSync(tmp.name)).toBeTrue(); 26 | 27 | const fileName = basename(tmp.name); 28 | 29 | if (options.prefix) { 30 | expect(fileName).toStartWith(options.prefix); 31 | } 32 | 33 | if (options.postfix) { 34 | expect(fileName).toEndWith(options.postfix); 35 | } 36 | 37 | const dir = dirname(tmp.name); 38 | 39 | if (options.tmpdir) { 40 | expect(dir).toBe(options.tmpdir); 41 | } 42 | 43 | const testData = "test content"; 44 | await handle.writeFile(testData); 45 | const content = await readFile(tmp.name, "utf8"); 46 | 47 | expect(content).toBe(testData); 48 | } 49 | 50 | expect(name).toBeDefined(); 51 | 52 | // Verify file is cleaned up 53 | expect(existsSync(name), `${name} still exists`).toBeFalse(); 54 | }, 55 | ); 56 | 57 | // Error cases 58 | it.each([ 59 | { 60 | description: "invalid directory", 61 | options: { tmpdir: "/nonexistent" }, 62 | expectedError: "ENOENT", 63 | }, 64 | ])("should handle errors for $description", () => { 65 | expect( 66 | tmpFileAsync({ 67 | tmpdir: "/nonexistent", 68 | }), 69 | ).rejects.toThrow(expect.objectContaining({ code: "ENOENT" })); 70 | }); 71 | 72 | it("creates files with the permissions specified", async () => { 73 | try { 74 | await using tmp = await tmpFileAsync({ 75 | // read-only for everyone 76 | mode: 0o444, 77 | }); 78 | 79 | await tmp.handle.writeFile("nonsense"); 80 | } catch (e) { 81 | expect(e).toMatchObject({ code: "EACCES" }); 82 | return; 83 | } 84 | 85 | expect().fail("Expected an error to be thrown"); 86 | }); 87 | 88 | // Testing using statement 89 | it("should cleanup file when used with 'using'", async () => { 90 | let tmpName: string; 91 | 92 | { 93 | await using tmp = await tmpFileAsync({}); 94 | tmpName = tmp.name; 95 | 96 | // Verify file exists within block 97 | expect(existsSync(tmp.name)).toBe(true); 98 | } 99 | 100 | // Verify file is cleaned up after block 101 | expect(existsSync(tmpName)).toBe(false); 102 | }); 103 | }); 104 | -------------------------------------------------------------------------------- /actions/lint-pr-title/src/tempfile.ts: -------------------------------------------------------------------------------- 1 | import { type FileOptions, file } from "tmp"; 2 | import fsPromises, { type FileHandle } from "node:fs/promises"; 3 | 4 | export async function tmpFileAsync( 5 | options: FileOptions, 6 | ): Promise<{ name: string; handle: FileHandle } & AsyncDisposable> { 7 | const { name } = await new Promise<{ 8 | name: string; 9 | }>((resolve, reject) => { 10 | file( 11 | { 12 | ...options, 13 | // We close and clean the file up ourselves 14 | discardDescriptor: true, 15 | detachDescriptor: true, 16 | keep: true, 17 | }, 18 | (err, name) => { 19 | if (err) { 20 | reject(err); 21 | } else { 22 | resolve({ name }); 23 | } 24 | }, 25 | ); 26 | }); 27 | 28 | // `tmp` returns a fd but it's much easier to work with a `FileHandle` so we 29 | // create one ourselves. 30 | const handle = await fsPromises.open(name, "w", options.mode ?? 0o600); 31 | 32 | return { 33 | name, 34 | handle, 35 | async [Symbol.asyncDispose]() { 36 | await handle.close(); 37 | 38 | await fsPromises.unlink(name); 39 | }, 40 | }; 41 | } 42 | -------------------------------------------------------------------------------- /actions/lint-pr-title/src/testUtils/context.ts: -------------------------------------------------------------------------------- 1 | import { Context } from "@actions/github/lib/context"; 2 | import { WebhookPayload } from "@actions/github/lib/interfaces"; 3 | import { Schema as WebhookSchema } from "@octokit/webhooks-types"; 4 | 5 | /** 6 | * Replace all `null` values in a type with `unknown`. The schema has specified 7 | * `null` for many fields where a value may be present but shouldn't be used. 8 | * Since the value is present, that means that real payloads don't satisfy the 9 | * interface. We can replace `null` with `unknown` to make the type more 10 | * permissive and allow the object to be typed. 11 | */ 12 | type DeepReplaceNullWithUnknown = T extends null 13 | ? unknown 14 | : T extends Array 15 | ? Array> 16 | : T extends object 17 | ? { [K in keyof T]: DeepReplaceNullWithUnknown } 18 | : T; 19 | 20 | /** 21 | * Allow extra fields in an object. This is useful for payloads where some extra 22 | * fields may be present that aren't in the schema. In that case the type 23 | * checker reports an `Object literal may only specify known properties` error. 24 | * This type allows such types to have extra fields. 25 | * 26 | */ 27 | type DeepAllowExtraFields = 28 | T extends Array 29 | ? Array> 30 | : T extends object 31 | ? { [K in keyof T]: DeepAllowExtraFields } & { 32 | [key: string]: unknown; 33 | } 34 | : T; 35 | 36 | /** 37 | * A combination of `DeepReplaceNullWithUnknown` and `DeepAllowExtraFields` to 38 | * allow real event payloads to be type checked. Use `satisfies` rather than a 39 | * type annotation so that the rest of the program uses the actual type, not 40 | * this one, which should allow the variable to be passed to other APIs. 41 | */ 42 | type RealWorldEventPayload = DeepAllowExtraFields< 43 | DeepReplaceNullWithUnknown 44 | >; 45 | 46 | export interface GitHubPayload { 47 | [key: string]: unknown; 48 | action: string; 49 | api_url: string; 50 | event: RealWorldEventPayload; 51 | event_name: string; 52 | graphql_url: string; 53 | job: string; 54 | repository: string; 55 | run_id: string; 56 | run_number: string; 57 | server_url: string; 58 | workflow: string; 59 | } 60 | 61 | /** 62 | * A temporary environment for use in tests. This class sets environment 63 | * variables in the constructor and unsets them with `dispose`. If the object is 64 | * instansiated with `using`, the dispose function will be called when the 65 | * object goes out of scope. 66 | */ 67 | class TempEnvironment implements Disposable { 68 | private readonly oldEnv: Record; 69 | 70 | constructor(readonly env: Record) { 71 | this.oldEnv = process.env; 72 | for (const key in env) { 73 | this.oldEnv[key] = process.env[key]; 74 | process.env[key] = env[key]; 75 | } 76 | } 77 | 78 | [Symbol.dispose]() { 79 | for (const [key, value] of Object.entries(this.oldEnv)) { 80 | if (value === undefined) { 81 | //eslint-disable-next-line @typescript-eslint/no-dynamic-delete 82 | delete process.env[key]; 83 | return; 84 | } 85 | process.env[key] = value; 86 | } 87 | } 88 | } 89 | 90 | export function newContext( 91 | payload: GitHubPayload, 92 | sha: string, 93 | ref: string, 94 | ): Context { 95 | // To create a new `Context()`, we need to set and then unset the various 96 | // `GITHUB_` environment variables. That makes this function non-thread-safe. 97 | using _env = new TempEnvironment({ 98 | GITHUB_EVENT_NAME: payload.event_name, 99 | GITHUB_SHA: sha, 100 | GITHUB_REF: ref, 101 | GITHUB_WORKFLOW: payload.workflow, 102 | GITHUB_ACTION: payload.action, 103 | GITHUB_JOB: payload.job, 104 | GITHUB_RUN_NUMBER: payload.run_number, 105 | GITHUB_RUN_ID: payload.run_id, 106 | GITHUB_API_URL: payload.api_url, 107 | GITHUB_GRAPHQL_URL: payload.graphql_url, 108 | GITHUB_SERVER_URL: payload.server_url, 109 | }); 110 | 111 | const ctx = new Context(); 112 | ctx.payload = payload.event as WebhookPayload; 113 | 114 | return ctx; 115 | } 116 | -------------------------------------------------------------------------------- /actions/lint-pr-title/src/testUtils/index.ts: -------------------------------------------------------------------------------- 1 | export { newContext } from "./context"; 2 | export type { GitHubPayload } from "./context"; 3 | export { newContextFromPullRequest } from "./pullRequestContext"; 4 | export { expect_toBeDefined } from "./tsMatchers"; 5 | -------------------------------------------------------------------------------- /actions/lint-pr-title/src/testUtils/tsMatchers.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "bun:test"; 2 | 3 | /** 4 | * Jest-style matchers don't narrow types, so you can't take advantage of what 5 | * you know after an `expect()`. This function narrows the type of a potentially 6 | * `undefined` value. 7 | */ 8 | export function expect_toBeDefined(arg: T): asserts arg is NonNullable { 9 | expect(arg).toBeDefined(); 10 | } 11 | -------------------------------------------------------------------------------- /actions/lint-pr-title/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "compilerOptions": { 4 | "allowJs": true, 5 | "checkJs": true, 6 | "esModuleInterop": true, 7 | "forceConsistentCasingInFileNames": true, 8 | "module": "es2022", 9 | "moduleResolution": "Bundler", 10 | "newLine": "lf", 11 | "noImplicitAny": true, 12 | "outDir": "./dist", 13 | "resolveJsonModule": true, 14 | "skipLibCheck": true, 15 | "sourceMap": true, 16 | "strict": true, 17 | "strictNullChecks": true, 18 | "target": "es2022" 19 | }, 20 | "include": ["**/*.ts"] 21 | } 22 | -------------------------------------------------------------------------------- /actions/login-to-gar/README.md: -------------------------------------------------------------------------------- 1 | # login-to-gar 2 | 3 | This is a composite GitHub Action, used to login to Google Artifact Registry (GAR). 4 | It uses [OIDC authentication](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect) 5 | which means that only workflows which get triggered based on certain rules can trigger these composite workflows. 6 | 7 | 8 | 9 | ```yaml 10 | name: CI 11 | on: 12 | pull_request: 13 | 14 | jobs: 15 | login: 16 | runs-on: ubuntu-latest 17 | # These permissions are needed to assume roles from Github's OIDC. 18 | permissions: 19 | contents: read 20 | id-token: write 21 | steps: 22 | - uses: grafana/shared-workflows/actions/login-to-gar@login-to-gar/v0.4.3 23 | id: login-to-gar 24 | with: 25 | registry: "" # e.g. us-docker.pkg.dev 26 | ``` 27 | 28 | 29 | 30 | ## Inputs 31 | 32 | | Name | Description | Default | 33 | | ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | ------------------- | 34 | | `registry` | Google Artifact Registry to authenticate against. | `us-docker.pkg.dev` | 35 | | `delete_credentials_file` | Delete the credentials file after the action is finished. If you want to keep the credentials file for a later step, set this to false. | `false` | 36 | 37 | > [!WARNING] 38 | > 39 | > 1. When using the `login-to-gar` action in GitHub Actions workflows, always place the `checkout` action before it. This is because the `login-to-gar` action stores Docker credentials in the workspace, and these credentials would be lost if the workspace is overwritten by a subsequent `checkout` action. The correct order makes sure that the Docker credentials persist throughout the workflow. 40 | > 2. Add `gha-creds-*.json` to your `.gitignore` and `.dockerignore` files to prevent accidentally committing credentials to your artifacts. ([source](https://github.com/google-github-actions/auth/blob/0920706a19e9d22c3d0da43d1db5939c6ad837a8/README.md#prerequisites)) 41 | -------------------------------------------------------------------------------- /actions/login-to-gar/action.yaml: -------------------------------------------------------------------------------- 1 | name: Login to artifact registry 2 | description: Composite action to push to Google Artifact Registry 3 | inputs: 4 | registry: 5 | description: | 6 | Google Artifact Registry to authenticate against. 7 | default: "us-docker.pkg.dev" 8 | delete_credentials_file: 9 | description: | 10 | Delete the credentials file after the action is finished. 11 | If you want to keep the credentials file for a later step, set this to false. 12 | default: "false" 13 | 14 | runs: 15 | using: composite 16 | steps: 17 | - uses: google-github-actions/auth@ba79af03959ebeac9769e648f473a284504d9193 # v2.1.10 18 | name: Auth with direct WIF 19 | id: auth_with_direct_wif 20 | with: 21 | project_id: "grafanalabs-workload-identity" 22 | workload_identity_provider: "projects/304398677251/locations/global/workloadIdentityPools/github/providers/github-provider" 23 | 24 | - name: Install docker-credential-gcr 25 | shell: bash 26 | env: 27 | DOCKER_CREDENTIAL_GCR_VERSION: "v2.1.28" 28 | run: | # zizmor: ignore[github-env] 29 | set -ex 30 | 31 | # Install docker-credential-gcr: 32 | # - if version is "tip", install from tip of main. 33 | # - if version is "latest-release", look up latest release. 34 | # - otherwise, install the specified version. 35 | case "${DOCKER_CREDENTIAL_GCR_VERSION}" in 36 | tip) 37 | echo "Installing docker-credential-gcr using go install" 38 | go install github.com/GoogleCloudPlatform/docker-credential-gcr@main 39 | ;; 40 | latest-release) 41 | tag=$(curl -L -s -u "username:${{ github.token }}" https://api.github.com/repos/GoogleCloudPlatform/docker-credential-gcr/releases/latest | jq -r '.tag_name') 42 | ;; 43 | *) 44 | tag="${DOCKER_CREDENTIAL_GCR_VERSION}" 45 | esac 46 | 47 | # Normalize OS name 48 | os="${{ runner.os }}" 49 | case "$os" in 50 | macOS) os="darwin" ;; 51 | Linux) os="linux" ;; 52 | Windows) os="windows" ;; 53 | *) echo "Unknown OS: $os"; exit 1 ;; 54 | esac 55 | 56 | # Map runner.arch to release asset arch 57 | arch="${{ runner.arch }}" 58 | case "$arch" in 59 | X64) arch="amd64" ;; 60 | ARM64) arch="arm64" ;; 61 | *) echo "Unsupported arch: $arch"; exit 1 ;; 62 | esac 63 | 64 | if [[ ! -z ${tag} ]]; then 65 | echo "Installing docker-credential-gcr @ ${tag} for ${os}/${arch}" 66 | mkdir -p "${RUNNER_TEMP}/docker-credential-gcr" 67 | curl -fsL "https://github.com/GoogleCloudPlatform/docker-credential-gcr/releases/download/${tag}/docker-credential-gcr_${os}_${arch}-${tag:1}.tar.gz" | tar xzf - -C "${RUNNER_TEMP}/docker-credential-gcr" docker-credential-gcr 68 | # Ignoring the github-env warning - docker-credential-gcr binary must be on the PATH for credHelpers in /.docker/config.json to work. 69 | # We are only adding a path to a binary that was just downloaded in RUNNER_TEMP (controlled by GitHub Actions). 70 | echo "${RUNNER_TEMP}/docker-credential-gcr" >> $GITHUB_PATH 71 | fi 72 | - name: "Configure GCP Artifact Registry" 73 | id: configure-docker 74 | shell: sh 75 | env: 76 | REGISTRY: ${{ inputs.registry }} 77 | run: docker-credential-gcr configure-docker --registries="${REGISTRY}" 78 | - name: Delete Google Application Credentials file 79 | shell: sh 80 | run: | 81 | if [ "${INPUTS_DELETE_CREDENTIALS_FILE}" = "true" ] && [ -n "${GOOGLE_APPLICATION_CREDENTIALS}" ]; then 82 | rm -f "${GOOGLE_APPLICATION_CREDENTIALS}" 83 | echo "::notice::Successfully deleted credentials file" 84 | else 85 | echo "::warning::Credentials file not found at ${GOOGLE_APPLICATION_CREDENTIALS}" 86 | fi 87 | env: 88 | INPUTS_DELETE_CREDENTIALS_FILE: ${{ inputs.delete_credentials_file }} 89 | GOOGLE_APPLICATION_CREDENTIALS: ${{ env.GOOGLE_APPLICATION_CREDENTIALS }} 90 | -------------------------------------------------------------------------------- /actions/login-to-gcs/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [0.2.1](https://github.com/grafana/shared-workflows/compare/login-to-gcs-v0.2.0...login-to-gcs/v0.2.1) (2025-06-04) 4 | 5 | 6 | ### 🐛 Bug Fixes 7 | 8 | * **everything:** fix all things for zizmor ([af9b0c5](https://github.com/grafana/shared-workflows/commit/af9b0c52635d39023136fb9312a354f91d9b2bfd)) 9 | * make default `delete_credentials_file` value false ([#950](https://github.com/grafana/shared-workflows/issues/950)) ([71ec5a1](https://github.com/grafana/shared-workflows/commit/71ec5a1861019932272c4ec12a8d7903049797c5)) 10 | 11 | 12 | ### 📝 Documentation 13 | 14 | * **multiple-actions:** move permissions to job level in workflow examples ([49c90b1](https://github.com/grafana/shared-workflows/commit/49c90b10fcbce463983bed45932cf468b8bd06ce)) 15 | * **multiple-actions:** move permissions to job level in workflows ([#969](https://github.com/grafana/shared-workflows/issues/969)) ([49c90b1](https://github.com/grafana/shared-workflows/commit/49c90b10fcbce463983bed45932cf468b8bd06ce)) 16 | * update all readmes to replace hyphen with slash ([#1008](https://github.com/grafana/shared-workflows/issues/1008)) ([472df76](https://github.com/grafana/shared-workflows/commit/472df76fb1cbb92a17fb9e055bdf0d1399109ee3)) 17 | 18 | 19 | ### 🤖 Continuous Integration 20 | 21 | * remove gcp credentials after composite action finishes ([#925](https://github.com/grafana/shared-workflows/issues/925)) ([62f8dda](https://github.com/grafana/shared-workflows/commit/62f8ddaa78b23147b22ba6a38df2b97963dab4b3)) 22 | 23 | 24 | ### 🔧 Miscellaneous Chores 25 | 26 | * **deps:** update google-github-actions/auth action to v2.1.10 ([#926](https://github.com/grafana/shared-workflows/issues/926)) ([fa48192](https://github.com/grafana/shared-workflows/commit/fa48192dac470ae356b3f7007229f3ac28c48a25)) 27 | * **deps:** update google-github-actions/auth action to v2.1.8 ([#740](https://github.com/grafana/shared-workflows/issues/740)) ([f75f620](https://github.com/grafana/shared-workflows/commit/f75f620c6800b60d1a31262154e90b5c7a3ee955)) 28 | * **deps:** update google-github-actions/auth action to v2.1.9 ([#924](https://github.com/grafana/shared-workflows/issues/924)) ([2774f26](https://github.com/grafana/shared-workflows/commit/2774f26e2321f825e20c85e424a1c6fa8298d820)) 29 | * fix changelog for login-to-gcs action ([#725](https://github.com/grafana/shared-workflows/issues/725)) ([f289c6b](https://github.com/grafana/shared-workflows/commit/f289c6b169d712f5025dfcdd4a3c361ee3e5ffa4)) 30 | * **main:** release push-to-gar-docker 0.3.0 ([#794](https://github.com/grafana/shared-workflows/issues/794)) ([a7bc536](https://github.com/grafana/shared-workflows/commit/a7bc5367c4a91c389526d58839d8f6224dba4dcc)) 31 | 32 | ## [0.2.0](https://github.com/grafana/shared-workflows/compare/login-to-gcs-v0.1.0...login-to-gcs-v0.2.0) (2025-01-28) 33 | 34 | 35 | ### 🎉 Features 36 | 37 | * add `service-account` input to `*-to-gcs` actions ([#720](https://github.com/grafana/shared-workflows/issues/720)) ([b4868e3](https://github.com/grafana/shared-workflows/commit/b4868e355b1e41a3ea54a272aa9970a809ec7ef1)) 38 | 39 | 40 | ### 🔧 Miscellaneous Chores 41 | 42 | * update readme when a new release is available ([#548](https://github.com/grafana/shared-workflows/issues/548)) ([9bf9163](https://github.com/grafana/shared-workflows/commit/9bf9163126c44247bcee6b6b9390eb488f9ead53)) 43 | 44 | ## 0.1.0 (2024-11-28) 45 | 46 | 47 | ### 🔧 Miscellaneous Chores 48 | 49 | * **deps:** update google-github-actions/auth action to v2.1.5 ([#248](https://github.com/grafana/shared-workflows/issues/248)) ([a5d1613](https://github.com/grafana/shared-workflows/commit/a5d1613fba998ba9b99b7267b6f9b915562da962)) 50 | * **deps:** update google-github-actions/auth action to v2.1.6 ([#436](https://github.com/grafana/shared-workflows/issues/436)) ([a275eef](https://github.com/grafana/shared-workflows/commit/a275eefa9f63e3bec05bd90ea77cfbbc9879afe8)) 51 | * **deps:** update google-github-actions/auth action to v2.1.7 ([#509](https://github.com/grafana/shared-workflows/issues/509)) ([41774d7](https://github.com/grafana/shared-workflows/commit/41774d7ebb3ca78e05aa6d2007e5e98c7a2fcf4f)) 52 | -------------------------------------------------------------------------------- /actions/login-to-gcs/README.md: -------------------------------------------------------------------------------- 1 | # login-to-gcs 2 | 3 | This is a composite GitHub Action, used to push objects to a bucket in Google Cloud Storage (GCS). 4 | It uses [OIDC authentication](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect) 5 | which means that only workflows which get triggered based on certain rules can 6 | trigger these composite workflows. 7 | 8 | 9 | 10 | ```yaml 11 | name: Login-to-gcs 12 | 13 | on: 14 | push: 15 | branches: 16 | - main 17 | 18 | jobs: 19 | login-to-gcs: 20 | name: login-to-gcs 21 | permissions: 22 | contents: read 23 | id-token: write 24 | steps: 25 | - uses: grafana/shared-workflows/actions/login-to-gcs@login-to-gcs/v0.2.1 26 | id: login-to-gcs 27 | ``` 28 | 29 | 30 | 31 | You can now use the shared-workflow `push-to-gcs` or gcloud to push objects from your CI pipeline. 32 | 33 | Ex: 34 | 35 | ``` 36 | $ gcloud storage cp OBJECT_LOCATION gs://DESTINATION_BUCKET_NAME 37 | ``` 38 | 39 | ## Inputs 40 | 41 | | Name | Type | Description | 42 | | ----------------- | ------ | ----------------------------------------------------------------------------------------------------------------- | 43 | | `bucket` | String | Name of bucket to upload to. Will default to grafanalabs-${repository.name}-${environment} | 44 | | `environment` | String | Environment for pushing artifacts (can be either dev or prod). | 45 | | `service_account` | String | Service account to use for authentication. Use it only when the service account is different than the default one | 46 | 47 | ## Outputs 48 | 49 | | Name | Type | Description | 50 | | -------- | ------ | --------------------------------------------- | 51 | | `bucket` | String | Name of the bucket that was authenticated to. | 52 | -------------------------------------------------------------------------------- /actions/login-to-gcs/action.yaml: -------------------------------------------------------------------------------- 1 | name: Login to GCS 2 | description: Composite action to login to Google Cloud Storage 3 | inputs: 4 | bucket: 5 | description: | 6 | Name of bucket to upload to. Will default to grafanalabs-${repository.name}-${environment} 7 | default: "" 8 | environment: 9 | description: | 10 | Environment for uploading objects (can be either dev or prod). 11 | default: dev 12 | service_account: 13 | description: | 14 | Custom service account to use for authentication. 15 | default: "" 16 | delete_credentials_file: 17 | description: | 18 | Delete the credentials file after the action is finished. 19 | If you want to keep the credentials file for a later step, set this to false. 20 | default: "false" 21 | 22 | outputs: 23 | bucket: 24 | description: "The name of the bucket that we have authenticated to." 25 | value: ${{ steps.construct-account-vars.outputs.bucket }} 26 | 27 | runs: 28 | using: composite 29 | steps: 30 | - name: Resolve GCP project 31 | id: resolve-project 32 | shell: bash 33 | run: | 34 | if [[ "${ENVIRONMENT}" == "dev" ]]; then 35 | PROJECT="grafanalabs-dev" 36 | elif [[ "${ENVIRONMENT}" == "prod" ]]; then 37 | PROJECT="grafanalabs-global" 38 | else 39 | echo "Invalid environment. Valid environment variable inputs: dev, prod" 40 | exit 1 41 | fi 42 | echo "project=${PROJECT}" | tee -a ${GITHUB_OUTPUT} 43 | env: 44 | ENVIRONMENT: ${{ inputs.environment }} 45 | - name: Construct dynamic account vars 46 | id: construct-account-vars 47 | shell: bash 48 | run: | 49 | # Construct repo name 50 | REPO_NAME=$(echo ${{ github.repository }} | awk -F'/' '{print $2}') 51 | echo "repo_name=${REPO_NAME}" | tee -a ${GITHUB_OUTPUT} 52 | 53 | # Construct bucket name 54 | if [[ "${BUCKET}" == "" ]]; then 55 | BUCKET="grafanalabs-${REPO_NAME}-${ENVIRONMENT}" 56 | else 57 | BUCKET="${BUCKET}" 58 | fi 59 | echo "bucket=${BUCKET}" | tee -a ${GITHUB_OUTPUT} 60 | 61 | # Construct service account 62 | if [[ "${SERVICE_ACCOUNT}" == "" ]]; then 63 | SERVICE_ACCOUNT="github-${{ github.repository_id }}-${ENVIRONMENT}-gcs@grafanalabs-workload-identity.iam.gserviceaccount.com" 64 | else 65 | SERVICE_ACCOUNT="${SERVICE_ACCOUNT}" 66 | fi 67 | echo "service_account=${SERVICE_ACCOUNT}" | tee -a ${GITHUB_OUTPUT} 68 | env: 69 | BUCKET: ${{ inputs.bucket }} 70 | ENVIRONMENT: ${{ inputs.environment }} 71 | SERVICE_ACCOUNT: ${{ inputs.service_account }} 72 | - uses: google-github-actions/auth@ba79af03959ebeac9769e648f473a284504d9193 # v2.1.10 73 | id: gcloud-auth 74 | with: 75 | workload_identity_provider: "projects/304398677251/locations/global/workloadIdentityPools/github/providers/github-provider" 76 | service_account: ${{ steps.construct-account-vars.outputs.service_account }} 77 | - name: Delete Google Application Credentials file 78 | if: ${{ inputs.delete_credentials_file == 'true' && env.GOOGLE_APPLICATION_CREDENTIALS != '' }} 79 | shell: sh 80 | run: | 81 | if [ -f "${{ env.GOOGLE_APPLICATION_CREDENTIALS }}" ]; then 82 | rm -f "${{ env.GOOGLE_APPLICATION_CREDENTIALS }}" 83 | echo "::notice::Successfully deleted credentials file" 84 | else 85 | echo "::warning::Credentials file not found at ${{ env.GOOGLE_APPLICATION_CREDENTIALS }}" 86 | fi 87 | -------------------------------------------------------------------------------- /actions/remove-checkout-credentials/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 0.1.0 (2025-05-12) 4 | 5 | 6 | ### 🎉 Features 7 | 8 | * Adding new remove-checkout-credentials-action ([285fbf5](https://github.com/grafana/shared-workflows/commit/285fbf5f9906624082821981f6b1612915ac2ba0)) 9 | * adding new remove-checkout-credentials-action ([#959](https://github.com/grafana/shared-workflows/issues/959)) ([285fbf5](https://github.com/grafana/shared-workflows/commit/285fbf5f9906624082821981f6b1612915ac2ba0)) 10 | 11 | 12 | ### 📝 Documentation 13 | 14 | * **multiple-actions:** move permissions to job level in workflow examples ([49c90b1](https://github.com/grafana/shared-workflows/commit/49c90b10fcbce463983bed45932cf468b8bd06ce)) 15 | * **multiple-actions:** move permissions to job level in workflows ([#969](https://github.com/grafana/shared-workflows/issues/969)) ([49c90b1](https://github.com/grafana/shared-workflows/commit/49c90b10fcbce463983bed45932cf468b8bd06ce)) 16 | 17 | 18 | ### 🔧 Miscellaneous Chores 19 | 20 | * **main:** release push-to-gar-docker 0.3.0 ([#794](https://github.com/grafana/shared-workflows/issues/794)) ([a7bc536](https://github.com/grafana/shared-workflows/commit/a7bc5367c4a91c389526d58839d8f6224dba4dcc)) 21 | -------------------------------------------------------------------------------- /actions/remove-checkout-credentials/README.md: -------------------------------------------------------------------------------- 1 | # remove-checkout-credentials 2 | 3 | This action can be used in combination with `actions/checkout` and removes credentials set by that action. 4 | For `actions/checkout` it is recommended to pass the `persist-credentials: false` setting but that might not be possible in various setups where the credentials _are_ needed for at least another action. 5 | `remove-checkout-credentials` is exactly for those cases, to act as cleanup. 6 | 7 | ## Example 8 | 9 | ```yaml 10 | name: CI 11 | on: 12 | pull_request: {} 13 | 14 | jobs: 15 | build: 16 | runs-on: ubuntu-latest 17 | permissions: 18 | contents: read 19 | steps: 20 | - uses: actions/checkout@v4 21 | with: 22 | persist-credentials: true 23 | 24 | # Actions that rely on the credentials within .git/config 25 | # ... 26 | 27 | - uses: grafana/shared-workflows/actions/remove-checkout-credentials@main 28 | 29 | # Actions that do not need the credentials anymore 30 | # ... 31 | ``` 32 | -------------------------------------------------------------------------------- /actions/remove-checkout-credentials/action.yaml: -------------------------------------------------------------------------------- 1 | name: Remove checkout credentials 2 | description: This action removes credentials stored by the actions/checkout action 3 | 4 | inputs: 5 | path: 6 | description: Path of the checkout 7 | 8 | runs: 9 | using: composite 10 | steps: 11 | - name: Remove credentials 12 | shell: bash 13 | env: 14 | CHECKOUT_PATH: "${{ inputs.path || '.' }}" 15 | run: | 16 | cd "${CHECKOUT_PATH}" 17 | 18 | set +e 19 | git config get --name-only --local core.sshCommand 2> /dev/null 20 | if [ "$?" == "0" ]; then 21 | export DELETE_SSH=true 22 | else 23 | export DELETE_SSH=false 24 | fi 25 | git config get --name-only --local http.https://github.com/.extraheader 2> /dev/null 26 | if [ "$?" == "0" ]; then 27 | export DELETE_HTTP=true 28 | else 29 | export DELETE_HTTP=false 30 | fi 31 | set -e 32 | 33 | # Delete the GITHUB_TOKEN if it's configured 34 | if [ "${DELETE_HTTP}" == "true" ]; then 35 | echo "::notice::Removing HTTP config" 36 | git config unset --local http.https://github.com/.extraheader && echo "::notice::HTTP config removed" 37 | fi 38 | 39 | # Delete the sshCommand if it's configured 40 | if [ "${DELETE_SSH}" == "true" ]; then 41 | echo "::notice::Removing SSH config" 42 | git config unset --local core.sshCommand && echo "::notice::SSH config removed" 43 | fi 44 | -------------------------------------------------------------------------------- /actions/send-slack-message/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [2.0.3](https://github.com/grafana/shared-workflows/compare/send-slack-message-v2.0.2...send-slack-message/v2.0.3) (2025-06-04) 4 | 5 | 6 | ### 📝 Documentation 7 | 8 | * **send-slack-notification:** remove outdated docs, url update ([#982](https://github.com/grafana/shared-workflows/issues/982)) ([d408247](https://github.com/grafana/shared-workflows/commit/d4082475390936b2952dcea4921ae423e2ce6395)) 9 | * update all readmes to replace hyphen with slash ([#1008](https://github.com/grafana/shared-workflows/issues/1008)) ([472df76](https://github.com/grafana/shared-workflows/commit/472df76fb1cbb92a17fb9e055bdf0d1399109ee3)) 10 | 11 | ## [2.0.2](https://github.com/grafana/shared-workflows/compare/send-slack-message-v2.0.1...send-slack-message-v2.0.2) (2025-05-08) 12 | 13 | 14 | ### 🐛 Bug Fixes 15 | 16 | * **everything:** fix all things for zizmor ([af9b0c5](https://github.com/grafana/shared-workflows/commit/af9b0c52635d39023136fb9312a354f91d9b2bfd)) 17 | 18 | 19 | ### 🔧 Miscellaneous Chores 20 | 21 | * **main:** release push-to-gar-docker 0.3.0 ([#794](https://github.com/grafana/shared-workflows/issues/794)) ([a7bc536](https://github.com/grafana/shared-workflows/commit/a7bc5367c4a91c389526d58839d8f6224dba4dcc)) 22 | 23 | ## [2.0.1](https://github.com/grafana/shared-workflows/compare/send-slack-message-v2.0.0...send-slack-message-v2.0.1) (2025-01-29) 24 | 25 | 26 | ### 📝 Documentation 27 | 28 | * update instructions after slack action v2 update ([#658](https://github.com/grafana/shared-workflows/issues/658)) ([077bbfe](https://github.com/grafana/shared-workflows/commit/077bbfebaf982b30cd01297eca94f9e3f02ccff9)) 29 | 30 | ## [2.0.0](https://github.com/grafana/shared-workflows/compare/send-slack-message-v1.0.0...send-slack-message-v2.0.0) (2024-12-17) 31 | 32 | ### BREAKING CHANGE 33 | 34 | * **deps:** update slackapi/slack-github-action action to v2 ([#534](https://github.com/grafana/shared-workflows/issues/534)) ([338682a](https://github.com/grafana/shared-workflows/commit/338682acb95238001a1ea995e660d229e78d4e20)) 35 | 36 | ### 🔧 Miscellaneous Chores 37 | 38 | * update readme when a new release is available ([#548](https://github.com/grafana/shared-workflows/issues/548)) ([9bf9163](https://github.com/grafana/shared-workflows/commit/9bf9163126c44247bcee6b6b9390eb488f9ead53)) 39 | 40 | ## 1.0.0 (2024-11-26) 41 | 42 | 43 | ### 🔧 Miscellaneous Chores 44 | 45 | * **deps:** update slackapi/slack-github-action action to v1.27.0 ([#264](https://github.com/grafana/shared-workflows/issues/264)) ([f790e79](https://github.com/grafana/shared-workflows/commit/f790e799f029dcfa2174d59263dbe7ff2a51452b)) 46 | * **deps:** update slackapi/slack-github-action action to v1.27.1 ([#533](https://github.com/grafana/shared-workflows/issues/533)) ([1a854a0](https://github.com/grafana/shared-workflows/commit/1a854a06dcab7421c2436ae585cf18af09112803)) 47 | -------------------------------------------------------------------------------- /actions/send-slack-message/action.yaml: -------------------------------------------------------------------------------- 1 | name: Send Slack Message 2 | description: Composite action to send a Slack message 3 | 4 | inputs: 5 | payload: 6 | description: "JSON payload to send" 7 | required: false 8 | method: 9 | description: "The Slack API method to call" 10 | required: true 11 | payload-templated: 12 | description: "To replace templated variables provided from the step env or default GitHub event context and payload, set the payload-templated variable to true" 13 | required: false 14 | outputs: 15 | time: 16 | value: ${{ steps.send-slack-message.outputs.time }} 17 | description: "The time that the Slack message was sent" 18 | thread_ts: 19 | value: ${{ steps.send-slack-message.outputs.thread_ts }} 20 | description: "The timestamp on the latest thread posted into Slack" 21 | ts: 22 | value: ${{ steps.send-slack-message.outputs.ts }} 23 | description: "The timestamp on the message that was posted into Slack" 24 | channel_id: 25 | value: ${{ steps.send-slack-message.outputs.channel_id }} 26 | description: "The channel id of the message that was posted into Slack" 27 | 28 | runs: 29 | using: composite 30 | steps: 31 | - name: Checkout shared workflows 32 | env: 33 | action_repo: ${{ github.action_repository }} 34 | action_ref: ${{ github.action_ref }} 35 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 36 | with: 37 | repository: ${{ env.action_repo }} 38 | ref: ${{ env.action_ref }} 39 | path: _shared-workflows-slack 40 | persist-credentials: false 41 | 42 | - name: Get a Slack token 43 | uses: ./_shared-workflows-slack/actions/get-vault-secrets 44 | with: 45 | common_secrets: | 46 | SLACK_BOT_TOKEN=slack-notifications:oauth-token 47 | - name: Send Slack Message 48 | id: send-slack-message 49 | uses: slackapi/slack-github-action@485a9d42d3a73031f12ec201c457e2162c45d02d # v2.0.0 50 | with: 51 | payload-templated: ${{ inputs.payload-templated }} 52 | method: ${{ inputs.method }} 53 | payload: ${{ inputs.payload }} 54 | token: ${{ env.SLACK_BOT_TOKEN }} 55 | 56 | # Cleanup checkout directory 57 | - name: Cleanup shared workflows checkout 58 | if: ${{ !cancelled() }} 59 | shell: bash 60 | run: | 61 | # Check that the directory looks OK before removing it 62 | if ! [ -d "_shared-workflows-slack/.git" ]; then 63 | echo "::warning Not removing shared workflows directory: doesn't look like a git repository" 64 | exit 0 65 | fi 66 | rm -rf _shared-workflows-slack 67 | -------------------------------------------------------------------------------- /actions/setup-argo/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [1.0.2](https://github.com/grafana/shared-workflows/compare/setup-argo-v1.0.1...setup-argo/v1.0.2) (2025-06-04) 4 | 5 | 6 | ### 🐛 Bug Fixes 7 | 8 | * **everything:** fix all things for zizmor ([af9b0c5](https://github.com/grafana/shared-workflows/commit/af9b0c52635d39023136fb9312a354f91d9b2bfd)) 9 | 10 | 11 | ### 📝 Documentation 12 | 13 | * **multiple-actions:** move permissions to job level in workflow examples ([49c90b1](https://github.com/grafana/shared-workflows/commit/49c90b10fcbce463983bed45932cf468b8bd06ce)) 14 | * **multiple-actions:** move permissions to job level in workflows ([#969](https://github.com/grafana/shared-workflows/issues/969)) ([49c90b1](https://github.com/grafana/shared-workflows/commit/49c90b10fcbce463983bed45932cf468b8bd06ce)) 15 | * update all readmes to replace hyphen with slash ([#1008](https://github.com/grafana/shared-workflows/issues/1008)) ([472df76](https://github.com/grafana/shared-workflows/commit/472df76fb1cbb92a17fb9e055bdf0d1399109ee3)) 16 | 17 | 18 | ### 🔧 Miscellaneous Chores 19 | 20 | * **deps:** update actions/cache action to v4.2.1 ([#788](https://github.com/grafana/shared-workflows/issues/788)) ([e26a7f2](https://github.com/grafana/shared-workflows/commit/e26a7f265ddef3a68c322a94a716e6453f656cba)) 21 | * **deps:** update actions/cache action to v4.2.2 ([#822](https://github.com/grafana/shared-workflows/issues/822)) ([0c036cd](https://github.com/grafana/shared-workflows/commit/0c036cdbfb4c912c287f0023073c4c07c10a76e7)) 22 | * **deps:** update actions/cache action to v4.2.3 ([#858](https://github.com/grafana/shared-workflows/issues/858)) ([bc9486e](https://github.com/grafana/shared-workflows/commit/bc9486e0e7cbe24b54d0dcdf8be459eb777567b0)) 23 | * **main:** release push-to-gar-docker 0.3.0 ([#794](https://github.com/grafana/shared-workflows/issues/794)) ([a7bc536](https://github.com/grafana/shared-workflows/commit/a7bc5367c4a91c389526d58839d8f6224dba4dcc)) 24 | 25 | ## [1.0.1](https://github.com/grafana/shared-workflows/compare/setup-argo-v1.0.0...setup-argo-v1.0.1) (2025-01-29) 26 | 27 | 28 | ### 🔧 Miscellaneous Chores 29 | 30 | * **deps:** update actions/cache action to v4.2.0 ([#636](https://github.com/grafana/shared-workflows/issues/636)) ([c4422fc](https://github.com/grafana/shared-workflows/commit/c4422fc4a4fa6cddae3862c7df7b4ec5f251053f)) 31 | * update readme when a new release is available ([#548](https://github.com/grafana/shared-workflows/issues/548)) ([9bf9163](https://github.com/grafana/shared-workflows/commit/9bf9163126c44247bcee6b6b9390eb488f9ead53)) 32 | 33 | ## 1.0.0 (2024-11-28) 34 | 35 | 36 | ### 🐛 Bug Fixes 37 | 38 | * **setup-argo:** less fragile OS/ARCH selection ([#222](https://github.com/grafana/shared-workflows/issues/222)) ([e9775f3](https://github.com/grafana/shared-workflows/commit/e9775f3ace2ef954b81548720476fb42ebde52e8)) 39 | * **setup-argo:** use amd64 as arch ([#217](https://github.com/grafana/shared-workflows/issues/217)) ([7a0ba14](https://github.com/grafana/shared-workflows/commit/7a0ba14ec0596297d38441c7829cbe8eb30fb036)) 40 | * **setup-argo:** use bash, fix idempotency, only restore if needed ([#221](https://github.com/grafana/shared-workflows/issues/221)) ([1e75822](https://github.com/grafana/shared-workflows/commit/1e75822620b1413e97deb7d60b10cad9ebf0fdeb)) 41 | * wrong linked action in argo docs ([#538](https://github.com/grafana/shared-workflows/issues/538)) ([170f6ab](https://github.com/grafana/shared-workflows/commit/170f6abb2b5e83be95d6b885c1f3a8e3e5200b57)) 42 | 43 | 44 | ### 🔧 Miscellaneous Chores 45 | 46 | * **deps:** update actions/cache action to v4.1.0 ([#441](https://github.com/grafana/shared-workflows/issues/441)) ([e583f36](https://github.com/grafana/shared-workflows/commit/e583f3676b58bba1b3a278be432b4220800abf2f)) 47 | * **deps:** update actions/cache action to v4.1.1 ([#448](https://github.com/grafana/shared-workflows/issues/448)) ([db270ac](https://github.com/grafana/shared-workflows/commit/db270ac9e0cd900940a87e7187c1d4863a997568)) 48 | * **deps:** update actions/cache action to v4.1.2 ([#494](https://github.com/grafana/shared-workflows/issues/494)) ([0f7e124](https://github.com/grafana/shared-workflows/commit/0f7e1244ff37782aaca907e8287d73173776646f)) 49 | * **deps:** update dsaltares/fetch-gh-release-asset action to v1.1.2 ([#247](https://github.com/grafana/shared-workflows/issues/247)) ([cfd4f70](https://github.com/grafana/shared-workflows/commit/cfd4f702bf0e979fe1f3d074154ab1616a7c4d75)) 50 | 51 | 52 | ### ♻️ Code Refactoring 53 | 54 | * **setup-argo:** refactor following feedback ([#215](https://github.com/grafana/shared-workflows/issues/215)) ([64a196a](https://github.com/grafana/shared-workflows/commit/64a196a127bcfe135cf6152a387db2024efc3044)) 55 | -------------------------------------------------------------------------------- /actions/setup-argo/README.md: -------------------------------------------------------------------------------- 1 | # Setup Argo 2 | 3 | Setup Argo cli and add it to the PATH, this action will pull the binary from GitHub releases and store it in cache for the next run. 4 | 5 | ## Example 6 | 7 | 8 | 9 | ```yaml 10 | uses: grafana/shared-workflows/actions/setup-argo@setup-argo/v1.0.2 11 | with: 12 | version: 1.0.2 # Version of the Argo CLI to install. 13 | ``` 14 | 15 | 16 | -------------------------------------------------------------------------------- /actions/setup-argo/action.yaml: -------------------------------------------------------------------------------- 1 | name: Setup Argo 2 | description: Setup Argo cli and add it to the PATH, this action will pull the binary from GitHub releases and store it in cache for the next run. 3 | 4 | inputs: 5 | cache-prefix: 6 | description: Prefix for the cache key. 7 | default: argo 8 | 9 | version: 10 | description: | 11 | Version of the Argo CLI to install. 12 | default: 3.5.1 13 | 14 | outputs: 15 | cache-hit: 16 | description: Whether the cache was hit or not. 17 | value: ${{ steps.cache.outputs.cache-hit || 'false' }} 18 | 19 | runs: 20 | using: composite 21 | 22 | steps: 23 | - name: Setup cache 24 | id: cache 25 | uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 26 | with: 27 | path: /usr/local/bin/argo 28 | key: ${{ inputs.cache-prefix }}-${{ runner.os }}-${{ runner.arch }}-${{ inputs.version }} 29 | 30 | - name: Map OS and ARCH to Argo release artifact 31 | id: os-arch 32 | if: steps.cache.outputs.cache-hit != 'true' 33 | shell: sh 34 | run: | 35 | echo "OS=$(go env GOOS)" | tee -a "${GITHUB_OUTPUT}" 36 | echo "ARCH=$(go env GOARCH)" | tee -a "${GITHUB_OUTPUT}" 37 | 38 | - name: Fetch Github Release Asset 39 | id: fetch_asset 40 | if: steps.cache.outputs.cache-hit != 'true' 41 | uses: dsaltares/fetch-gh-release-asset@aa2ab1243d6e0d5b405b973c89fa4d06a2d0fff7 # 1.1.2 42 | with: 43 | repo: "argoproj/argo-workflows" 44 | version: "tags/v${{ inputs.version }}" 45 | file: "argo-${{ steps.os-arch.outputs.OS }}-${{ steps.os-arch.outputs.ARCH }}${{ steps.os-arch.outputs.OS == 'windows' && '.exe' || '' }}.gz" 46 | target: /usr/local/bin/argo.gz 47 | 48 | - name: gunzip 49 | id: gunzip 50 | if: steps.fetch_asset.outcome == 'success' 51 | shell: sh 52 | run: | 53 | # Overwrite the argo binary if it already exists. We assume it's from a 54 | # previous run of this action. 55 | gunzip --force /usr/local/bin/argo.gz 56 | chmod +x /usr/local/bin/argo 57 | -------------------------------------------------------------------------------- /actions/setup-conftest/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [1.0.2](https://github.com/grafana/shared-workflows/compare/setup-conftest-v1.0.1...setup-conftest/v1.0.2) (2025-06-04) 4 | 5 | 6 | ### 🐛 Bug Fixes 7 | 8 | * **everything:** fix all things for zizmor ([af9b0c5](https://github.com/grafana/shared-workflows/commit/af9b0c52635d39023136fb9312a354f91d9b2bfd)) 9 | 10 | 11 | ### 📝 Documentation 12 | 13 | * **multiple-actions:** move permissions to job level in workflow examples ([49c90b1](https://github.com/grafana/shared-workflows/commit/49c90b10fcbce463983bed45932cf468b8bd06ce)) 14 | * **multiple-actions:** move permissions to job level in workflows ([#969](https://github.com/grafana/shared-workflows/issues/969)) ([49c90b1](https://github.com/grafana/shared-workflows/commit/49c90b10fcbce463983bed45932cf468b8bd06ce)) 15 | * update all readmes to replace hyphen with slash ([#1008](https://github.com/grafana/shared-workflows/issues/1008)) ([472df76](https://github.com/grafana/shared-workflows/commit/472df76fb1cbb92a17fb9e055bdf0d1399109ee3)) 16 | 17 | 18 | ### 🔧 Miscellaneous Chores 19 | 20 | * **deps:** update actions/cache action to v4.2.1 ([#788](https://github.com/grafana/shared-workflows/issues/788)) ([e26a7f2](https://github.com/grafana/shared-workflows/commit/e26a7f265ddef3a68c322a94a716e6453f656cba)) 21 | * **deps:** update actions/cache action to v4.2.2 ([#822](https://github.com/grafana/shared-workflows/issues/822)) ([0c036cd](https://github.com/grafana/shared-workflows/commit/0c036cdbfb4c912c287f0023073c4c07c10a76e7)) 22 | * **deps:** update actions/cache action to v4.2.3 ([#858](https://github.com/grafana/shared-workflows/issues/858)) ([bc9486e](https://github.com/grafana/shared-workflows/commit/bc9486e0e7cbe24b54d0dcdf8be459eb777567b0)) 23 | * **main:** release push-to-gar-docker 0.3.0 ([#794](https://github.com/grafana/shared-workflows/issues/794)) ([a7bc536](https://github.com/grafana/shared-workflows/commit/a7bc5367c4a91c389526d58839d8f6224dba4dcc)) 24 | 25 | ## [1.0.1](https://github.com/grafana/shared-workflows/compare/setup-conftest-v1.0.0...setup-conftest-v1.0.1) (2025-01-28) 26 | 27 | 28 | ### 🔧 Miscellaneous Chores 29 | 30 | * **deps:** update actions/cache action to v4.2.0 ([#636](https://github.com/grafana/shared-workflows/issues/636)) ([c4422fc](https://github.com/grafana/shared-workflows/commit/c4422fc4a4fa6cddae3862c7df7b4ec5f251053f)) 31 | * update readme when a new release is available ([#548](https://github.com/grafana/shared-workflows/issues/548)) ([9bf9163](https://github.com/grafana/shared-workflows/commit/9bf9163126c44247bcee6b6b9390eb488f9ead53)) 32 | 33 | ## 1.0.0 (2024-11-28) 34 | 35 | 36 | ### 🎉 Features 37 | 38 | * add setup-conftest action ([#212](https://github.com/grafana/shared-workflows/issues/212)) ([6a252ee](https://github.com/grafana/shared-workflows/commit/6a252ee32cc3109533ce51789842d3ed78e6abf2)) 39 | 40 | 41 | ### 🐛 Bug Fixes 42 | 43 | * **setup-conftest:** normalize runner.os ([#216](https://github.com/grafana/shared-workflows/issues/216)) ([318d33e](https://github.com/grafana/shared-workflows/commit/318d33e1f443b2f511a21593f1945e9e026c86d0)) 44 | 45 | 46 | ### 🔧 Miscellaneous Chores 47 | 48 | * **deps:** update actions/cache action to v4.1.0 ([#441](https://github.com/grafana/shared-workflows/issues/441)) ([e583f36](https://github.com/grafana/shared-workflows/commit/e583f3676b58bba1b3a278be432b4220800abf2f)) 49 | * **deps:** update actions/cache action to v4.1.1 ([#448](https://github.com/grafana/shared-workflows/issues/448)) ([db270ac](https://github.com/grafana/shared-workflows/commit/db270ac9e0cd900940a87e7187c1d4863a997568)) 50 | * **deps:** update actions/cache action to v4.1.2 ([#494](https://github.com/grafana/shared-workflows/issues/494)) ([0f7e124](https://github.com/grafana/shared-workflows/commit/0f7e1244ff37782aaca907e8287d73173776646f)) 51 | * **deps:** update dsaltares/fetch-gh-release-asset action to v1.1.2 ([#247](https://github.com/grafana/shared-workflows/issues/247)) ([cfd4f70](https://github.com/grafana/shared-workflows/commit/cfd4f702bf0e979fe1f3d074154ab1616a7c4d75)) 52 | -------------------------------------------------------------------------------- /actions/setup-conftest/README.md: -------------------------------------------------------------------------------- 1 | # Setup Conftest 2 | 3 | Setup conftest and add it to the PATH, this action will pull the binary from GitHub releases and store it in cache for the next run. 4 | 5 | ## Example 6 | 7 | 8 | 9 | ```yaml 10 | uses: grafana/shared-workflows/actions/setup-conftest@setup-conftest/v1.0.2 11 | with: 12 | version: 1.0.2 # Version of conftest to install. 13 | ``` 14 | 15 | 16 | -------------------------------------------------------------------------------- /actions/setup-conftest/action.yaml: -------------------------------------------------------------------------------- 1 | name: Setup Conftest 2 | description: Setup conftest and add it to the PATH, this action will pull the binary from GitHub releases and store it in cache for the next run. 3 | 4 | inputs: 5 | version: 6 | description: | 7 | Version of conftest to install. 8 | default: 0.55.0 9 | 10 | runs: 11 | using: composite 12 | 13 | steps: 14 | - name: Setup cache 15 | id: cache 16 | uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 17 | with: 18 | path: /usr/local/bin/conftest 19 | key: conftest-${{ runner.os }}-${{ runner.arch }}-${{ inputs.version }} 20 | 21 | - if: runner.os == 'macOS' 22 | shell: sh 23 | run: echo "OS=Darwin" >> "$GITHUB_ENV" 24 | 25 | # runner.arch options: X86, X64, ARM, or ARM64. 26 | # conftest release: arm64, x86_64, ppc64le, s390x. 27 | # If it ain't arm64 or x86_64, it'll fall back to runner.arch. 28 | - if: runner.arch == 'X64' 29 | shell: sh 30 | run: echo "ARCH=x86_64" >> "$GITHUB_ENV" 31 | 32 | - if: runner.arch == 'ARM64' 33 | shell: sh 34 | run: echo "ARCH=arm64" >> "$GITHUB_ENV" 35 | 36 | - name: Fetch Github Release Asset 37 | id: fetch_asset 38 | if: steps.cache.outputs.cache-hit != 'true' 39 | uses: dsaltares/fetch-gh-release-asset@aa2ab1243d6e0d5b405b973c89fa4d06a2d0fff7 # 1.1.2 40 | with: 41 | repo: "open-policy-agent/conftest" 42 | version: "tags/v${{ inputs.version }}" 43 | file: "conftest_${{ inputs.version }}_${{ env.OS || runner.os }}_${{ env.ARCH || runner.arch }}.tar.gz" 44 | target: ${{ runner.temp }}/conftest.tgz 45 | 46 | - name: Unpack tarball 47 | id: unpack 48 | if: steps.fetch_asset.outcome == 'success' 49 | shell: sh 50 | run: | 51 | tar -zxvf ${{ runner.temp }}/conftest.tgz conftest 52 | mv conftest /usr/local/bin 53 | chmod +x /usr/local/bin/conftest 54 | -------------------------------------------------------------------------------- /actions/setup-jrsonnet/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [1.0.1](https://github.com/grafana/shared-workflows/compare/setup-jrsonnet-v1.0.0...setup-jrsonnet/v1.0.1) (2025-06-04) 4 | 5 | 6 | ### 🐛 Bug Fixes 7 | 8 | * **everything:** fix all things for zizmor ([af9b0c5](https://github.com/grafana/shared-workflows/commit/af9b0c52635d39023136fb9312a354f91d9b2bfd)) 9 | 10 | 11 | ### 📝 Documentation 12 | 13 | * **multiple-actions:** move permissions to job level in workflow examples ([49c90b1](https://github.com/grafana/shared-workflows/commit/49c90b10fcbce463983bed45932cf468b8bd06ce)) 14 | * **multiple-actions:** move permissions to job level in workflows ([#969](https://github.com/grafana/shared-workflows/issues/969)) ([49c90b1](https://github.com/grafana/shared-workflows/commit/49c90b10fcbce463983bed45932cf468b8bd06ce)) 15 | * update all readmes to replace hyphen with slash ([#1008](https://github.com/grafana/shared-workflows/issues/1008)) ([472df76](https://github.com/grafana/shared-workflows/commit/472df76fb1cbb92a17fb9e055bdf0d1399109ee3)) 16 | 17 | 18 | ### 🔧 Miscellaneous Chores 19 | 20 | * **deps:** update actions/cache action to v4.2.1 ([#788](https://github.com/grafana/shared-workflows/issues/788)) ([e26a7f2](https://github.com/grafana/shared-workflows/commit/e26a7f265ddef3a68c322a94a716e6453f656cba)) 21 | * **deps:** update actions/cache action to v4.2.2 ([#822](https://github.com/grafana/shared-workflows/issues/822)) ([0c036cd](https://github.com/grafana/shared-workflows/commit/0c036cdbfb4c912c287f0023073c4c07c10a76e7)) 22 | * **deps:** update actions/cache action to v4.2.3 ([#858](https://github.com/grafana/shared-workflows/issues/858)) ([bc9486e](https://github.com/grafana/shared-workflows/commit/bc9486e0e7cbe24b54d0dcdf8be459eb777567b0)) 23 | * **main:** release push-to-gar-docker 0.3.0 ([#794](https://github.com/grafana/shared-workflows/issues/794)) ([a7bc536](https://github.com/grafana/shared-workflows/commit/a7bc5367c4a91c389526d58839d8f6224dba4dcc)) 24 | 25 | ## 1.0.0 (2025-01-29) 26 | 27 | 28 | ### 🎉 Features 29 | 30 | * introduce setup-jrsonnet action ([#619](https://github.com/grafana/shared-workflows/issues/619)) ([c4c7060](https://github.com/grafana/shared-workflows/commit/c4c706001d0f3c9cc6a9fcea394b071b2b33e52f)) 31 | 32 | 33 | ### 🔧 Miscellaneous Chores 34 | 35 | * **deps:** update actions/cache action to v4.2.0 ([#636](https://github.com/grafana/shared-workflows/issues/636)) ([c4422fc](https://github.com/grafana/shared-workflows/commit/c4422fc4a4fa6cddae3862c7df7b4ec5f251053f)) 36 | -------------------------------------------------------------------------------- /actions/setup-jrsonnet/README.md: -------------------------------------------------------------------------------- 1 | # Setup jrsonnet 2 | 3 | Setup jrsonnet CLI and add it to the PATH, this action will pull the binary from GitHub releases and store it in cache for the next run. 4 | 5 | ## Example 6 | 7 | 8 | 9 | ```yaml 10 | uses: grafana/shared-workflows/actions/setup-jrsonnet@setup-jrsonnet/v1.0.1 11 | with: 12 | version: 1.0.1 # Version of the jrsonnet CLI to install. 13 | ``` 14 | 15 | 16 | -------------------------------------------------------------------------------- /actions/setup-jrsonnet/action.yaml: -------------------------------------------------------------------------------- 1 | name: Setup jrsonnet 2 | description: Setup jrsonnet CLI and add it to the PATH, this action will pull the binary from GitHub releases and store it in cache for the next run. 3 | 4 | inputs: 5 | cache-prefix: 6 | description: Prefix for the cache key. 7 | default: jrsonnet 8 | 9 | version: 10 | description: | 11 | Version of the jrsonnet CLI to install. 12 | default: 0.5.0-pre96-test 13 | 14 | outputs: 15 | cache-hit: 16 | description: Whether the cache was hit or not. 17 | value: ${{ steps.cache.outputs.cache-hit || 'false' }} 18 | 19 | runs: 20 | using: composite 21 | 22 | steps: 23 | - name: Setup cache 24 | id: cache 25 | uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 26 | with: 27 | path: /usr/local/bin/jrsonnet 28 | key: ${{ inputs.cache-prefix }}-${{ runner.os }}-${{ runner.arch }}-${{ inputs.version }} 29 | 30 | - name: Map OS and ARCH to jrsonnet release artifact 31 | id: os-arch 32 | if: steps.cache.outputs.cache-hit != 'true' 33 | shell: sh 34 | run: | 35 | echo "OS=$(go env GOOS)" | tee -a "${GITHUB_OUTPUT}" 36 | echo "ARCH=$(go env GOARCH)" | tee -a "${GITHUB_OUTPUT}" 37 | 38 | - name: Fetch GitHub Release Asset 39 | id: fetch_asset 40 | if: steps.cache.outputs.cache-hit != 'true' 41 | uses: dsaltares/fetch-gh-release-asset@aa2ab1243d6e0d5b405b973c89fa4d06a2d0fff7 # 1.1.2 42 | with: 43 | repo: "CertainLach/jrsonnet" 44 | version: "tags/v${{ inputs.version }}" 45 | file: "jrsonnet-${{ steps.os-arch.outputs.OS }}-${{ steps.os-arch.outputs.ARCH }}" 46 | target: /usr/local/bin/jrsonnet 47 | 48 | - name: make executable 49 | id: executable 50 | if: steps.fetch_asset.outcome == 'success' 51 | shell: sh 52 | run: | 53 | chmod +x /usr/local/bin/jrsonnet 54 | -------------------------------------------------------------------------------- /actions/techdocs-rewrite-relative-links/README.md: -------------------------------------------------------------------------------- 1 | # Techdocs: Rewrite relative links 2 | 3 | **Note:** This action is intended to be primarily used within the publish-techdocs workflow. 4 | 5 | This action's job is to scan through all the Markdown files inside the docs 6 | folder (based on the presence of an `mkdocs.yml` file) and rewrite relative 7 | links that point to files _outside_ that docs folder folder to absolute ones. 8 | 9 | ## Usage 10 | 11 | The following example will check out the shared-workflows project and run the action from it. 12 | The action will then check inside the working directory if there is a `mkdocs.yml` file and process the docs mentioned in there. 13 | 14 | Assuming that the docs folder for mkdocs is located at `/workspace/docs` and there is a `filename.md` in there with content like this: 15 | 16 | ```markdown 17 | [outside link](../README.md) 18 | ``` 19 | 20 | Then this link inside the file will be changed to ... 21 | 22 | ```markdown 23 | [outside link](https://github.com/grafana/reponame/blob/main/README.md) 24 | ``` 25 | 26 | 27 | 28 | ```yaml 29 | - id: checkout-shared-workflows 30 | name: Checkout shared workflows 31 | uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v1.0.2 32 | with: 33 | repository: grafana/shared-workflows 34 | ref: techdocs-rewrite-relative-links-v1.0.2 35 | path: _shared-workflows 36 | persist-credentials: false 37 | 38 | - name: Rewrite relative links 39 | uses: ./_shared-workflows/actions/techdocs-rewrite-relative-links 40 | with: 41 | working-directory: ./ 42 | repo-url: "https://github.com/${{ github.repository }}" 43 | default-branch: "${{ github.event.repository.default_branch }}" 44 | dry-run: false 45 | 46 | # Since the previous step already checked out the shared-workflows repo, we can use that: 47 | checkout-action-repository: true 48 | checkout-action-repository-path: _shared-workflows 49 | ``` 50 | 51 | 52 | 53 | Follow that up with the actions that should publish the docs to EngHub. See [the `publish-techdocs.yaml` workflow](https://github.com/grafana/shared-workflows/blob/main/.github/workflows/publish-techdocs.yaml) for details. 54 | 55 | ## Inputs 56 | 57 | | Name | Type | Description | 58 | | ------------------------------------------------------ | ------- | -------------------------------------------------------------------------------------------------------------- | 59 | | `default-branch` (required) | string | Default branch name of the repository | 60 | | `repo-url` (required) | string | Full URL to the GitHub repository | 61 | | `working-directory` (required) | string | Directory containing the `mkdocs.yml` file | 62 | | `dry-run` | boolean | Do not modify the files but print a diff | 63 | | `checkout-action-repository-path` (default: `_action`) | string | Folder where the repository should be checked out to for running the action or where a checkout already exists | 64 | | `checkout-action-repository` (default: `true`) | boolean | If the workflow already checks out the shared-workflows repository, you can set this to false | 65 | | `verbose` (default `false`) | boolean | Log on info level | 66 | | `debug` (default `false`) | boolean | Log on debug level | 67 | -------------------------------------------------------------------------------- /actions/techdocs-rewrite-relative-links/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/grafana/shared-workflows/actions/techdocs-rewrite-relative-links 2 | 3 | go 1.23.4 4 | 5 | toolchain go1.24.1 6 | 7 | require ( 8 | github.com/aymanbagabas/go-udiff v0.3.1 9 | github.com/lmittmann/tint v1.1.2 10 | github.com/neilotoole/slogt v1.1.0 11 | github.com/spf13/afero v1.14.0 12 | github.com/stretchr/testify v1.10.0 13 | github.com/teekennedy/goldmark-markdown v0.5.1 14 | github.com/urfave/cli/v2 v2.27.6 15 | github.com/willabides/actionslog v0.5.1 16 | github.com/yuin/goldmark v1.7.12 17 | golang.org/x/term v0.32.0 18 | gopkg.in/yaml.v3 v3.0.1 19 | ) 20 | 21 | require ( 22 | github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect 23 | github.com/davecgh/go-spew v1.1.1 // indirect 24 | github.com/fatih/color v1.10.0 // indirect 25 | github.com/goccy/go-yaml v1.11.0 // indirect 26 | github.com/kr/pretty v0.1.0 // indirect 27 | github.com/mattn/go-colorable v0.1.8 // indirect 28 | github.com/mattn/go-isatty v0.0.12 // indirect 29 | github.com/pmezard/go-difflib v1.0.0 // indirect 30 | github.com/russross/blackfriday/v2 v2.1.0 // indirect 31 | github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect 32 | golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect 33 | golang.org/x/sys v0.33.0 // indirect 34 | golang.org/x/text v0.23.0 // indirect 35 | golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect 36 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect 37 | ) 38 | -------------------------------------------------------------------------------- /actions/trigger-argo-workflow/README.md: -------------------------------------------------------------------------------- 1 | # Trigger Argo Workflow Action 2 | 3 | > [!NOTE] 4 | > If you are at Grafana Labs, see the [internal documentation](https://enghub.grafana-ops.net/docs/default/component/deployment-tools/platform/continuous-delivery/argo-workflows/#triggering-a-workflow-from-github-actions) for information on how to set up Argo Workflows and configure them to be triggerable by this action. 5 | 6 | This GitHub action triggers an Argo workflow in one of the Grafana Labs Argo 7 | Workflows instances. It contains a small wrapper around the `argo` CLI, which is 8 | downloaded as part of the action. 9 | 10 | As our Argo Workflows instances require authentication, this workflow will only 11 | work when triggered from a `grafana`-owned repository. We would welcome 12 | contributions to extend this action to work with any instance, or you are free 13 | to fork and modify to run on your own instances. See [#21][issue-21]. 14 | 15 | [issue-21]: https://github.com/grafana/shared-workflows/issues/21 16 | 17 | ## How to use 18 | 19 | ## Inputs 20 | 21 | - `instance`: The instance to use (`dev` or `ops`). Defaults to `ops`. 22 | - `namespace`: Required. The namespace to trigger the workflow in. 23 | - `parameters`: The newline-separated parameters to pass to the Argo workflow. Example: 24 | 25 | ```yaml 26 | parameters: | 27 | param1=value1 28 | param2=value2 29 | ``` 30 | 31 | - `workflow_template`: The workflow template to use. Required if `command` is `submit` (the default). 32 | - `extra_args`: Extra arguments to pass to the Argo CLI. Example: `--generate-name foo-` 33 | - `log_level`: The log level to use. Choose from `debug`, `info`, `warn` or `error`. Defaults to `info`. 34 | 35 | ## Outputs 36 | 37 | - `uri`: The URI of the workflow that was created. 38 | 39 | ## Required permissions 40 | 41 | This action needs a couple of explicit `GITHUB_TOKEN` scopes because it: 42 | 43 | - authenticates to Vault via GitHub OIDC (needs **`id-token: write`**) 44 | - checks out / reads Go files from the repo (needs **`contents: read`**) 45 | 46 | Ideally, place these permissions at the job level to avoid zizmor flagging them as [excessive permissions](https://woodruffw.github.io/zizmor/audits/#excessive-permissions). 47 | 48 | ```yaml 49 | permissions: 50 | contents: read # allows actions/checkout and setup-go to read the repo 51 | id-token: write # allows get-vault-secrets to create an OIDC token for Vault 52 | ``` 53 | 54 | ## Usage 55 | 56 | Here is an example of how to use this action: 57 | 58 | 59 | 60 | ```yaml 61 | name: Trigger Argo Workflow 62 | on: 63 | pull_request: 64 | 65 | jobs: 66 | trigger-argo-workflow: 67 | runs-on: ubuntu-latest 68 | permissions: 69 | contents: read 70 | id-token: write 71 | steps: 72 | - name: Trigger Argo Workflow 73 | uses: grafana/shared-workflows/actions/trigger-argo-workflow@0f705663f602e305aa22034489f351dc7022d8ce # trigger-argo-workflow-v1.1.1 74 | with: 75 | instance: "ops" 76 | namespace: "mynamespace" 77 | workflow_template: "hello" 78 | parameters: | 79 | message=world 80 | extra_args: "--generate-name hello-world-" 81 | log_level: "debug" 82 | ``` 83 | 84 | 85 | -------------------------------------------------------------------------------- /actions/trigger-argo-workflow/cmd/trigger-argo-workflow/argoflags.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "regexp" 6 | "strings" 7 | 8 | "github.com/kelseyhightower/envconfig" 9 | ) 10 | 11 | // sanitisedString is a string which conforms with 12 | // https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#syntax-and-character-set 13 | var labelValueRegexp = regexp.MustCompile(`[^-A-Za-z0-9_.]`) 14 | 15 | type sanitisedString string 16 | 17 | func (s *sanitisedString) Decode(str string) error { 18 | *s = sanitisedString(labelValueRegexp.ReplaceAllString(str, "")) 19 | return nil 20 | } 21 | 22 | type RepoInfo struct { 23 | Name string 24 | Owner string 25 | } 26 | 27 | func (r *RepoInfo) Decode(text string) error { 28 | split := strings.SplitN(text, "/", 2) 29 | if len(split) != 2 { 30 | return fmt.Errorf("invalid repository format") 31 | } 32 | r.Owner, r.Name = labelValueRegexp.ReplaceAllString(split[0], ""), labelValueRegexp.ReplaceAllString(split[1], "") 33 | return nil 34 | } 35 | 36 | func (r RepoInfo) ToArgs() string { 37 | return fmt.Sprintf( 38 | "trigger-repo-name=%s,trigger-repo-owner=%s", 39 | r.Name, 40 | r.Owner, 41 | ) 42 | } 43 | 44 | // GitHubActionsMetadata contains the metadata provided by GitHub Actions in 45 | // environment variables, which is used to populate labels on the Argo Workflow. 46 | type GitHubActionsMetadata struct { 47 | BuildNumber sanitisedString `envconfig:"GITHUB_RUN_NUMBER"` 48 | Commit sanitisedString `envconfig:"GITHUB_SHA"` 49 | CommitAuthor sanitisedString `envconfig:"GITHUB_ACTOR"` 50 | Repo RepoInfo `envconfig:"GITHUB_REPOSITORY"` 51 | BuildEvent sanitisedString `envconfig:"GITHUB_EVENT_NAME"` 52 | } 53 | 54 | func NewGitHubActionsMetadata() (GitHubActionsMetadata, error) { 55 | var m GitHubActionsMetadata 56 | err := envconfig.Process("", &m) 57 | if err != nil { 58 | return m, fmt.Errorf("failed to parse environment variables: %w", err) 59 | } 60 | return m, nil 61 | } 62 | 63 | func (m GitHubActionsMetadata) ToArgs() []string { 64 | var z GitHubActionsMetadata 65 | if m == z { 66 | return []string{} 67 | } 68 | 69 | return []string{ 70 | "--labels", 71 | strings.Join([]string{ 72 | fmt.Sprintf("trigger-build-number=%s", m.BuildNumber), 73 | fmt.Sprintf("trigger-commit=%s", m.Commit), 74 | fmt.Sprintf("trigger-commit-author=%s", m.CommitAuthor), 75 | m.Repo.ToArgs(), 76 | fmt.Sprintf("trigger-event=%s", m.BuildEvent), 77 | }, ","), 78 | } 79 | } 80 | 81 | func (a App) args(m GitHubActionsMetadata) []string { 82 | // Force the labels when the command is `submit` 83 | addCILabels := a.addCILabels || a.command == "submit" 84 | 85 | var args []string 86 | if addCILabels { 87 | args = m.ToArgs() 88 | } 89 | 90 | if a.workflowTemplate != "" { 91 | args = append( 92 | args, 93 | "--from", 94 | fmt.Sprintf("workflowtemplate/%s", a.workflowTemplate), 95 | ) 96 | } 97 | 98 | args = append( 99 | args, 100 | "--loglevel", 101 | strings.ToLower(a.levelVar.Level().String()), 102 | a.command, 103 | ) 104 | 105 | args = append(args, a.extraArgs...) 106 | 107 | return args 108 | } 109 | -------------------------------------------------------------------------------- /actions/trigger-argo-workflow/cmd/trigger-argo-workflow/argoflags_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log/slog" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/require" 8 | ) 9 | 10 | func TestBuildCommand(t *testing.T) { 11 | testCases := []struct { 12 | name string 13 | command string 14 | addCILabels bool 15 | logLevel string 16 | expectedError bool 17 | expectedOutput []string 18 | envVars map[string]string 19 | }{ 20 | { 21 | name: "Add labels to submit command", 22 | command: "submit", 23 | addCILabels: true, 24 | logLevel: "info", 25 | expectedOutput: []string{"--labels", "trigger-build-number=1,trigger-commit=abc,trigger-commit-author=actor,trigger-repo-name=repo,trigger-repo-owner=owner,trigger-event=event", "--loglevel", "info", "submit"}, 26 | envVars: map[string]string{ 27 | "GITHUB_RUN_NUMBER": "1", 28 | "GITHUB_SHA": "abc", 29 | "GITHUB_ACTOR": "actor", 30 | "GITHUB_REPOSITORY": "owner/repo", 31 | "GITHUB_EVENT_NAME": "event", 32 | }, 33 | }, 34 | { 35 | name: "No labels when addCILabels is false", 36 | command: "stop", 37 | addCILabels: false, 38 | logLevel: "info", 39 | expectedOutput: []string{"--loglevel", "info", "stop"}, 40 | envVars: map[string]string{ 41 | "GITHUB_RUN_NUMBER": "2", 42 | "GITHUB_SHA": "abc", 43 | "GITHUB_ACTOR": "actor", 44 | "GITHUB_REPOSITORY": "owner/repo", 45 | "GITHUB_EVENT_NAME": "event", 46 | }, 47 | }, 48 | { 49 | name: "Invalid repository format", 50 | command: "submit", 51 | addCILabels: true, 52 | logLevel: "info", 53 | expectedError: true, 54 | envVars: map[string]string{ 55 | "GITHUB_RUN_NUMBER": "3", 56 | "GITHUB_SHA": "abc", 57 | "GITHUB_ACTOR": "actor", 58 | "GITHUB_REPOSITORY": "invalid", 59 | "GITHUB_EVENT_NAME": "event", 60 | }, 61 | }, 62 | } 63 | 64 | for _, tc := range testCases { 65 | t.Run(tc.name, func(t *testing.T) { 66 | for k, v := range tc.envVars { 67 | t.Setenv(k, v) 68 | } 69 | 70 | level, err := parseLogLevel(tc.logLevel) 71 | require.NoError(t, err) 72 | 73 | var lv slog.LevelVar 74 | lv.Set(level) 75 | 76 | a := App{ 77 | levelVar: &lv, 78 | 79 | addCILabels: tc.addCILabels, 80 | 81 | command: tc.command, 82 | } 83 | 84 | md, err := NewGitHubActionsMetadata() 85 | if tc.expectedError { 86 | require.Error(t, err) 87 | return 88 | } else { 89 | require.NoError(t, err) 90 | } 91 | 92 | output := a.args(md) 93 | require.Equal(t, tc.expectedOutput, output) 94 | }) 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /actions/trigger-argo-workflow/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/grafana/shared-workflows/actions/trigger-argo-workflow 2 | 3 | go 1.23.1 4 | 5 | require ( 6 | github.com/cenkalti/backoff/v4 v4.3.0 7 | github.com/kelseyhightower/envconfig v1.4.0 8 | github.com/lmittmann/tint v1.1.2 9 | github.com/stretchr/testify v1.10.0 10 | github.com/urfave/cli/v2 v2.27.6 11 | github.com/willabides/actionslog v0.5.1 12 | golang.org/x/term v0.32.0 13 | ) 14 | 15 | require ( 16 | github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect 17 | github.com/davecgh/go-spew v1.1.1 // indirect 18 | github.com/fatih/color v1.10.0 // indirect 19 | github.com/goccy/go-yaml v1.11.0 // indirect 20 | github.com/mattn/go-colorable v0.1.8 // indirect 21 | github.com/mattn/go-isatty v0.0.12 // indirect 22 | github.com/pmezard/go-difflib v1.0.0 // indirect 23 | github.com/russross/blackfriday/v2 v2.1.0 // indirect 24 | github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect 25 | golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect 26 | golang.org/x/sys v0.33.0 // indirect 27 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect 28 | gopkg.in/yaml.v3 v3.0.1 // indirect 29 | ) 30 | -------------------------------------------------------------------------------- /actions/validate-policy-bot-config/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [1.1.1](https://github.com/grafana/shared-workflows/compare/validate-policy-bot-config-v1.1.0...validate-policy-bot-config/v1.1.1) (2025-06-04) 4 | 5 | 6 | ### 🐛 Bug Fixes 7 | 8 | * ensure every action disables git credential persistence ([#821](https://github.com/grafana/shared-workflows/issues/821)) ([31ebf3f](https://github.com/grafana/shared-workflows/commit/31ebf3f8e5d0f8709e6ec4ef73b39dd2bd08f959)) 9 | * **everything:** fix all things for zizmor ([af9b0c5](https://github.com/grafana/shared-workflows/commit/af9b0c52635d39023136fb9312a354f91d9b2bfd)) 10 | 11 | 12 | ### 📝 Documentation 13 | 14 | * **multiple-actions:** move permissions to job level in workflow examples ([49c90b1](https://github.com/grafana/shared-workflows/commit/49c90b10fcbce463983bed45932cf468b8bd06ce)) 15 | * **multiple-actions:** move permissions to job level in workflows ([#969](https://github.com/grafana/shared-workflows/issues/969)) ([49c90b1](https://github.com/grafana/shared-workflows/commit/49c90b10fcbce463983bed45932cf468b8bd06ce)) 16 | * update all readmes to replace hyphen with slash ([#1008](https://github.com/grafana/shared-workflows/issues/1008)) ([472df76](https://github.com/grafana/shared-workflows/commit/472df76fb1cbb92a17fb9e055bdf0d1399109ee3)) 17 | 18 | 19 | ### 🔧 Miscellaneous Chores 20 | 21 | * **main:** release push-to-gar-docker 0.3.0 ([#794](https://github.com/grafana/shared-workflows/issues/794)) ([a7bc536](https://github.com/grafana/shared-workflows/commit/a7bc5367c4a91c389526d58839d8f6224dba4dcc)) 22 | 23 | ## [1.1.0](https://github.com/grafana/shared-workflows/compare/validate-policy-bot-config-v1.0.0...validate-policy-bot-config-v1.1.0) (2025-01-29) 24 | 25 | 26 | ### 🎉 Features 27 | 28 | * **docs:** added EngHub doc links to corresponding actions readmes ([#635](https://github.com/grafana/shared-workflows/issues/635)) ([a7d04c1](https://github.com/grafana/shared-workflows/commit/a7d04c1e98496dbf07f8e44602933af07ba62f9f)) 29 | 30 | ## 1.0.0 (2024-11-29) 31 | 32 | 33 | ### 🎉 Features 34 | 35 | * add validate-policy-bot-action ([#497](https://github.com/grafana/shared-workflows/issues/497)) ([29ab6fb](https://github.com/grafana/shared-workflows/commit/29ab6fb539bd10865fb0d06a8f21113d48ee2668)) 36 | * add workflow to check for non-releasable actions ([#588](https://github.com/grafana/shared-workflows/issues/588)) ([e16bf1a](https://github.com/grafana/shared-workflows/commit/e16bf1ac180d7b6c9c13a6e556b24e0f7dc0d57c)) 37 | -------------------------------------------------------------------------------- /actions/validate-policy-bot-config/README.md: -------------------------------------------------------------------------------- 1 | # validate-policy-bot-config 2 | 3 | Validates the `.policy.yml` configuration file for [Policy Bot](https://github.com/palantir/policy-bot). 4 | 5 | See [Policy Bot's documentation](https://github.com/palantir/policy-bot?tab=readme-ov-file#configuration) for more information. 6 | 7 | ## Inputs 8 | 9 | - `validation_endpoint`: The endpoint to validate the configuration against. Defaults to `https://policy-bot.grafana.net/api/v1/validate`. 10 | 11 | Example workflow: 12 | 13 | 14 | 15 | ```yaml 16 | name: validate-policy-bot 17 | on: 18 | pull_request: 19 | paths: 20 | - ".policy.yml" 21 | push: 22 | paths: 23 | - ".policy.yml" 24 | 25 | jobs: 26 | validate-policy-bot: 27 | runs-on: ubuntu-latest 28 | steps: 29 | - name: Checkout 30 | uses: actions/checkout@v4 31 | with: 32 | persist-credentials: false 33 | - name: Validate Policy Bot configuration 34 | uses: grafana/shared-workflows/actions/validate-policy-bot-config@validate-policy-bot-config/v1.1.1 35 | ``` 36 | 37 | 38 | -------------------------------------------------------------------------------- /actions/validate-policy-bot-config/action.yml: -------------------------------------------------------------------------------- 1 | name: Validate Policy Bot Config 2 | description: Validates the Policy Bot configuration file. 3 | 4 | inputs: 5 | validation_endpoint: 6 | description: | 7 | Validation API endpoint. 8 | default: https://github-policy-bot.grafana-ops.net/api/validate 9 | 10 | runs: 11 | using: composite 12 | steps: 13 | - name: Validate Policy Bot config 14 | env: 15 | VALIDATION_ENDPOINT: ${{ inputs.validation_endpoint }} 16 | shell: bash 17 | run: | 18 | curl \ 19 | --silent \ 20 | --fail-with-body \ 21 | --request PUT \ 22 | --upload-file .policy.yml \ 23 | "${VALIDATION_ENDPOINT}" 24 | -------------------------------------------------------------------------------- /release-please-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json", 3 | "changelog-sections": [ 4 | { 5 | "section": "🎉 Features", 6 | "type": "feat" 7 | }, 8 | { 9 | "section": "🐛 Bug Fixes", 10 | "type": "fix" 11 | }, 12 | { 13 | "section": "⚡ Performance Improvements", 14 | "type": "perf" 15 | }, 16 | { 17 | "section": "🔗 Dependencies", 18 | "type": "deps" 19 | }, 20 | { 21 | "section": "📝 Documentation", 22 | "type": "docs" 23 | }, 24 | { 25 | "section": "🏗️ Build System", 26 | "type": "build" 27 | }, 28 | { 29 | "section": "🤖 Continuous Integration", 30 | "type": "ci" 31 | }, 32 | { 33 | "section": "🔧 Miscellaneous Chores", 34 | "type": "chore" 35 | }, 36 | { 37 | "section": "⏪ Reverts", 38 | "type": "revert" 39 | }, 40 | { 41 | "section": "✅ Tests", 42 | "type": "test" 43 | }, 44 | { 45 | "section": "💄 Style", 46 | "type": "style" 47 | }, 48 | { 49 | "section": "♻️ Code Refactoring", 50 | "type": "refactor" 51 | } 52 | ], 53 | "draft-pull-request": true, 54 | "include-v-in-tag": true, 55 | "packages": { 56 | "actions/argo-lint": { 57 | "package-name": "argo-lint", 58 | "extra-files": ["README.md"] 59 | }, 60 | "actions/aws-auth": { 61 | "package-name": "aws-auth", 62 | "extra-files": ["README.md"] 63 | }, 64 | "actions/build-push-to-dockerhub": { 65 | "package-name": "build-push-to-dockerhub", 66 | "extra-files": ["README.md"] 67 | }, 68 | "actions/dockerhub-login": { 69 | "package-name": "dockerhub-login", 70 | "extra-files": ["README.md"] 71 | }, 72 | "actions/find-pr-for-commit": { 73 | "package-name": "find-pr-for-commit", 74 | "extra-files": ["README.md"] 75 | }, 76 | "actions/generate-openapi-clients": { 77 | "package-name": "generate-openapi-clients", 78 | "extra-files": ["README.md"] 79 | }, 80 | "actions/get-vault-secrets": { 81 | "package-name": "get-vault-secrets", 82 | "extra-files": ["README.md"] 83 | }, 84 | "actions/lint-pr-title": { 85 | "package-name": "lint-pr-title", 86 | "extra-files": ["README.md"] 87 | }, 88 | "actions/login-to-gar": { 89 | "package-name": "login-to-gar", 90 | "extra-files": ["README.md"] 91 | }, 92 | "actions/login-to-gcs": { 93 | "package-name": "login-to-gcs", 94 | "extra-files": ["README.md"] 95 | }, 96 | "actions/push-to-gar-docker": { 97 | "package-name": "push-to-gar-docker", 98 | "extra-files": ["README.md"] 99 | }, 100 | "actions/push-to-gcs": { 101 | "package-name": "push-to-gcs", 102 | "extra-files": ["README.md"] 103 | }, 104 | "actions/remove-checkout-credentials": { 105 | "package-name": "remove-checkout-credentials", 106 | "extra-files": ["README.md"], 107 | "initial-version": "0.1.0" 108 | }, 109 | "actions/send-slack-message": { 110 | "package-name": "send-slack-message", 111 | "extra-files": ["README.md"] 112 | }, 113 | "actions/setup-argo": { 114 | "package-name": "setup-argo", 115 | "extra-files": ["README.md"] 116 | }, 117 | "actions/setup-jrsonnet": { 118 | "package-name": "setup-jrsonnet", 119 | "extra-files": ["README.md"] 120 | }, 121 | "actions/setup-conftest": { 122 | "package-name": "setup-conftest", 123 | "extra-files": ["README.md"] 124 | }, 125 | "actions/techdocs-rewrite-relative-links": { 126 | "package-name": "techdocs-rewrite-relative-links", 127 | "extra-files": ["README.md"] 128 | }, 129 | "actions/trigger-argo-workflow": { 130 | "package-name": "trigger-argo-workflow", 131 | "extra-files": ["README.md"] 132 | }, 133 | "actions/validate-policy-bot-config": { 134 | "package-name": "validate-policy-bot-config", 135 | "extra-files": ["README.md"] 136 | }, 137 | "actions/dependabot-auto-triage": { 138 | "package-name": "dependabot-auto-triage", 139 | "extra-files": ["README.md"] 140 | }, 141 | "actions/get-latest-workflow-artifact": { 142 | "package-name": "get-latest-workflow-artifact", 143 | "extra-files": ["README.md"], 144 | "initial-version": "0.1.0" 145 | } 146 | }, 147 | "release-type": "simple", 148 | "tag-separator": "/", 149 | "separate-pull-requests": true 150 | } 151 | -------------------------------------------------------------------------------- /scripts/generate-catalog-info/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/grafana/shared-workflows/scripts/generate-catalog-info 2 | 3 | go 1.24.2 4 | 5 | require ( 6 | github.com/hairyhenderson/go-codeowners v0.7.0 7 | k8s.io/apimachinery v0.33.0 8 | sigs.k8s.io/yaml v1.4.0 9 | ) 10 | 11 | require ( 12 | github.com/go-logr/logr v1.4.2 // indirect 13 | github.com/kr/text v0.2.0 // indirect 14 | github.com/rogpeppe/go-internal v1.14.1 // indirect 15 | k8s.io/klog/v2 v2.130.1 // indirect 16 | k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect 17 | ) 18 | -------------------------------------------------------------------------------- /scripts/generate-catalog-info/go.sum: -------------------------------------------------------------------------------- 1 | github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 2 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 3 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 4 | github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= 5 | github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= 6 | github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 7 | github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= 8 | github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= 9 | github.com/hairyhenderson/go-codeowners v0.7.0 h1:s0W4wF8bdsBEjTWzwzSlsatSthWtTAF2xLgo4a4RwAo= 10 | github.com/hairyhenderson/go-codeowners v0.7.0/go.mod h1:wUlNgQ3QjqC4z8DnM5nnCYVq/icpqXJyJOukKx5U8/Q= 11 | github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= 12 | github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= 13 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 14 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 15 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 16 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 17 | github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= 18 | github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= 19 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= 20 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 21 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 22 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= 23 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 24 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 25 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 26 | k8s.io/apimachinery v0.33.0 h1:1a6kHrJxb2hs4t8EE5wuR/WxKDwGN1FKH3JvDtA0CIQ= 27 | k8s.io/apimachinery v0.33.0/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM= 28 | k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= 29 | k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= 30 | k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro= 31 | k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= 32 | sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= 33 | sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= 34 | --------------------------------------------------------------------------------