From 70882e8b3a645f4bb09008590ecee33e91f7a6da Mon Sep 17 00:00:00 2001 From: Michael Anderson Date: Mon, 4 May 2026 17:52:33 -0400 Subject: [PATCH 1/4] Updating to prevent unsigned plugins from being pushed to dev by default, but setting the option for it to be overriden. Also granting the merge queue bot permisisons to sign plugins. --- .github/workflows/cd.yml | 8 ++++++++ .github/workflows/ci.yml | 17 ++++++++++++++--- tests/act/internal/workflow/ci/ci.go | 2 ++ 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 68da9d1e9..48d2893e7 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -101,6 +101,13 @@ on: type: boolean required: false default: false + allow-unsigned-in-dev: + description: | + Escape hatch: when true, restore the pre-v8 behaviour of auto-allowing unsigned dev builds in untrusted contexts. + Defaults to false (untrusted dev builds hard-fail). See ci.yml for details. + type: boolean + required: false + default: false signature-type: description: Specify signature type to use when signing the plugin type: string @@ -789,6 +796,7 @@ jobs: environment: ${{ inputs.environment }} allow-unsigned: ${{ inputs.allow-unsigned }} + allow-unsigned-in-dev: ${{ inputs.allow-unsigned-in-dev }} signature-type: ${{ inputs.signature-type }} dist-artifacts-prefix: ${{ inputs.dist-artifacts-prefix }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6b416d91d..34dc2e649 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -229,6 +229,13 @@ on: type: boolean required: false default: false + allow-unsigned-in-dev: + description: | + Escape hatch: when true, restore the pre-v8 behaviour of auto-allowing unsigned dev builds in untrusted contexts. + Defaults to false (untrusted dev builds hard-fail). PR/fork builds (env=`none`|`''`) keep the fallback either way. + type: boolean + required: false + default: false signature-type: description: Specify signature type to use when signing the plugin type: string @@ -381,7 +388,9 @@ jobs: 'dependabot[bot]', 'renovate-sh-app[bot]', // Used by other shared workflows such as the version bump workflow - 'grafana-plugins-platform-bot[bot]' + 'grafana-plugins-platform-bot[bot]', + // Only the actor on post-merge pushes from the queue, which already required maintainer approval. + 'github-merge-queue[bot]' ].map((s) => s.toLowerCase()); const isPR = context.eventName === 'pull_request'; @@ -540,6 +549,8 @@ jobs: secrets: ${{ (fromJson(steps.workflow-context.outputs.result).isTrusted && inputs.backend-secrets != '') && inputs.backend-secrets || '' }} build-target: ${{ inputs.backend-build-target }} + # Auto-allow-unsigned applies only to untrusted contexts AND envs where shipping unsigned is acceptable: + # `none`/`''` (CI-only) and, opt-in via `allow-unsigned-in-dev`, `dev`. Untrusted dev otherwise hard-fails here. - name: Package universal ZIP id: universal-zip uses: grafana/plugin-ci-workflows/actions/internal/plugins/package@main @@ -548,7 +559,7 @@ jobs: dist-folder: ${{ inputs.plugin-directory }}/dist output-folder: ${{ inputs.plugin-directory }}/dist-artifacts access-policy-token: ${{ fromJson(steps.workflow-context.outputs.result).isTrusted && fromJSON(steps.get-secrets.outputs.secrets).SIGN_PLUGIN_ACCESS_POLICY_TOKEN || '' }} - allow-unsigned: ${{ ((inputs.environment == 'dev' || inputs.environment == '' || inputs.environment == 'none') && !(fromJson(steps.workflow-context.outputs.result).isTrusted)) || inputs.allow-unsigned }} + allow-unsigned: ${{ ((inputs.environment == '' || inputs.environment == 'none' || (inputs.environment == 'dev' && inputs.allow-unsigned-in-dev)) && !(fromJson(steps.workflow-context.outputs.result).isTrusted)) || inputs.allow-unsigned }} signature-type: ${{ inputs.signature-type }} - name: Package os/arch ZIPs @@ -559,7 +570,7 @@ jobs: dist-folder: ${{ inputs.plugin-directory }}/dist output-folder: ${{ inputs.plugin-directory }}/dist-artifacts access-policy-token: ${{ fromJson(steps.workflow-context.outputs.result).isTrusted && fromJSON(steps.get-secrets.outputs.secrets).SIGN_PLUGIN_ACCESS_POLICY_TOKEN || '' }} - allow-unsigned: ${{ ((inputs.environment == 'dev' || inputs.environment == '' || inputs.environment == 'none') && !(fromJson(steps.workflow-context.outputs.result).isTrusted)) || inputs.allow-unsigned }} + allow-unsigned: ${{ ((inputs.environment == '' || inputs.environment == 'none' || (inputs.environment == 'dev' && inputs.allow-unsigned-in-dev)) && !(fromJson(steps.workflow-context.outputs.result).isTrusted)) || inputs.allow-unsigned }} signature-type: ${{ inputs.signature-type }} - name: Trufflehog secrets scanning diff --git a/tests/act/internal/workflow/ci/ci.go b/tests/act/internal/workflow/ci/ci.go index 4b5f10ab8..c1f1940c9 100644 --- a/tests/act/internal/workflow/ci/ci.go +++ b/tests/act/internal/workflow/ci/ci.go @@ -110,6 +110,7 @@ type WorkflowInputs struct { RunTruffleHog *bool AllowUnsigned *bool + AllowUnsignedInDev *bool Testing *bool BackendBuildTarget *string @@ -138,6 +139,7 @@ func SetCIInputs(dst *workflow.Job, inputs WorkflowInputs) { workflow.SetJobInput(dst, "run-trufflehog", inputs.RunTruffleHog) workflow.SetJobInput(dst, "allow-unsigned", inputs.AllowUnsigned) + workflow.SetJobInput(dst, "allow-unsigned-in-dev", inputs.AllowUnsignedInDev) workflow.SetJobInput(dst, "testing", inputs.Testing) workflow.SetJobInput(dst, "backend-build-target", inputs.BackendBuildTarget) From a5f5a3827c9a61203b13958d3dc7defeaf1f6c9f Mon Sep 17 00:00:00 2001 From: Michael Anderson Date: Tue, 5 May 2026 20:40:02 -0400 Subject: [PATCH 2/4] adding a test --- tests/act/internal/workflow/ci/ci_test.go | 67 +++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 tests/act/internal/workflow/ci/ci_test.go diff --git a/tests/act/internal/workflow/ci/ci_test.go b/tests/act/internal/workflow/ci/ci_test.go new file mode 100644 index 000000000..a562c809c --- /dev/null +++ b/tests/act/internal/workflow/ci/ci_test.go @@ -0,0 +1,67 @@ +package ci + +import ( + "testing" + + "github.com/grafana/plugin-ci-workflows/tests/act/internal/workflow" + "github.com/stretchr/testify/require" +) + +// newJobWithEmptyInputs returns a fresh Job with an initialized With map. +// SetCIInputs writes into job.With, so callers must ensure it is non-nil. +func newJobWithEmptyInputs() *workflow.Job { + return &workflow.Job{With: map[string]any{}} +} + +func TestSetCIInputs_AllowUnsignedInDev(t *testing.T) { + t.Parallel() + + const inputKey = "allow-unsigned-in-dev" + + t.Run("nil leaves input unset (workflow default applies)", func(t *testing.T) { + t.Parallel() + + job := newJobWithEmptyInputs() + SetCIInputs(job, WorkflowInputs{}) + + require.NotContains(t, job.With, inputKey, + "unset AllowUnsignedInDev should not propagate %q so the workflow's default (false) applies", inputKey) + }) + + t.Run("true is forwarded as the escape-hatch opt-in", func(t *testing.T) { + t.Parallel() + + job := newJobWithEmptyInputs() + SetCIInputs(job, WorkflowInputs{ + AllowUnsignedInDev: workflow.Input(true), + }) + + require.Equal(t, true, job.With[inputKey], + "AllowUnsignedInDev=true must propagate as %q=true to opt back into the pre-v8 untrusted-dev fallback", inputKey) + }) + + t.Run("false is forwarded explicitly", func(t *testing.T) { + t.Parallel() + + job := newJobWithEmptyInputs() + SetCIInputs(job, WorkflowInputs{ + AllowUnsignedInDev: workflow.Input(false), + }) + + require.Equal(t, false, job.With[inputKey], + "AllowUnsignedInDev=false must propagate as %q=false to keep the hard-fail default", inputKey) + }) + + t.Run("does not collide with allow-unsigned", func(t *testing.T) { + t.Parallel() + + job := newJobWithEmptyInputs() + SetCIInputs(job, WorkflowInputs{ + AllowUnsigned: workflow.Input(true), + AllowUnsignedInDev: workflow.Input(false), + }) + + require.Equal(t, true, job.With["allow-unsigned"], "AllowUnsigned should map to %q", "allow-unsigned") + require.Equal(t, false, job.With[inputKey], "AllowUnsignedInDev should map to %q", inputKey) + }) +} From ab00067090c50f9b24d0d5b97771902f22a5ebcd Mon Sep 17 00:00:00 2001 From: Michael Anderson <67813367+manderson-dev@users.noreply.github.com> Date: Wed, 6 May 2026 08:41:28 -0400 Subject: [PATCH 3/4] Update .github/workflows/ci.yml Co-authored-by: Giuseppe Guerra --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 34dc2e649..e8a7d55dc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -231,7 +231,7 @@ on: default: false allow-unsigned-in-dev: description: | - Escape hatch: when true, restore the pre-v8 behaviour of auto-allowing unsigned dev builds in untrusted contexts. + Escape hatch: when true, allow unsigned dev builds in untrusted contexts. Defaults to false (untrusted dev builds hard-fail). PR/fork builds (env=`none`|`''`) keep the fallback either way. type: boolean required: false From 8938c8029bb2637096db8e695eb7440a4f32d180 Mon Sep 17 00:00:00 2001 From: Michael Anderson <67813367+manderson-dev@users.noreply.github.com> Date: Fri, 15 May 2026 16:49:22 -0400 Subject: [PATCH 4/4] Update .github/workflows/cd.yml Co-authored-by: Giuseppe Guerra --- .github/workflows/cd.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 48d2893e7..eae93539d 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -103,7 +103,7 @@ on: default: false allow-unsigned-in-dev: description: | - Escape hatch: when true, restore the pre-v8 behaviour of auto-allowing unsigned dev builds in untrusted contexts. + Escape hatch: when true, allowing unsigned dev builds in untrusted contexts. Defaults to false (untrusted dev builds hard-fail). See ci.yml for details. type: boolean required: false