Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions acceptance/examples/happy_config_with_public_key.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
# Policy config that includes a publicKey - for testing issue #1528
# ec validate input should work even when publicKey is specified
publicKey: "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAERhr8Zj4dZW67zucg8fDr11M4lmRp\nzN6SIcIjkvH39siYg1DkCoa2h2xMUZ10ecbM3/ECqvBV55YwQ2rcIEa7XQ==\n-----END PUBLIC KEY-----"
sources:
- policy:
- "git::https://${GITHOST}/git/happy-day-policy.git"
32 changes: 32 additions & 0 deletions features/__snapshots__/validate_input.snap
Original file line number Diff line number Diff line change
Expand Up @@ -139,3 +139,35 @@ success: true
[multiple data source top level key map merging:stderr - 1]

---

[valid policy URL with publicKey in policy config:stdout - 1]
{
"success": true,
"filepaths": [
{
"filepath": "pipeline_definition.yaml",
"violations": [],
"warnings": [],
"successes": null,
"success": true,
"success-count": 1
}
],
"policy": {
"sources": [
{
"policy": [
"git::https://${GITHOST}/git/happy-day-policy.git"
]
}
],
"publicKey": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAERhr8Zj4dZW67zucg8fDr11M4lmRp\nzN6SIcIjkvH39siYg1DkCoa2h2xMUZ10ecbM3/ECqvBV55YwQ2rcIEa7XQ==\n-----END PUBLIC KEY-----"
},
"ec-version": "${EC_VERSION}",
"effective-time": "${TIMESTAMP}"
}
---

[valid policy URL with publicKey in policy config:stderr - 1]

---
24 changes: 24 additions & 0 deletions features/validate_input.feature
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,30 @@ Feature: validate input
Then the exit status should be 0
Then the output should match the snapshot

# Test for issue #1528: ec validate input should work when policy has publicKey
Scenario: valid policy URL with publicKey in policy config
Given a git repository named "happy-day-config-with-public-key" with
| policy.yaml | examples/happy_config_with_public_key.yaml |
Given a git repository named "happy-day-policy" with
| main.rego | examples/happy_day.rego |
Given a pipeline definition file named "pipeline_definition.yaml" containing
"""
---
apiVersion: tekton.dev/v1
kind: Pipeline
metadata:
name: basic-build
spec:
tasks:
- name: appstudio-init
taskRef:
name: init
version: "0.1"
"""
When ec command is run with "validate input --file pipeline_definition.yaml --policy git::https://${GITHOST}/git/happy-day-config-with-public-key.git --output json"
Then the exit status should be 0
Then the output should match the snapshot

Scenario: valid policy URL with text output
Given a git repository named "happy-day-config" with
| policy.yaml | examples/happy_config.yaml |
Expand Down
21 changes: 19 additions & 2 deletions internal/policy/policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"context"
"crypto"
_ "embed"
"encoding/pem"
"errors"
"fmt"
"os"
Expand Down Expand Up @@ -92,14 +93,24 @@ type policy struct {
skipImageSigCheck bool
}

// PublicKeyPEM returns the PublicKey in PEM format.
// PublicKeyPEM returns the PublicKey in PEM format. When SigVerifier is not
// initialized, the policy's PublicKey is returned only if it is already valid
// PEM; otherwise an error is returned so callers do not treat non-PEM data as PEM.
func (p *policy) PublicKeyPEM() ([]byte, error) {
// Public key is not involved when using keyless verification
if p.Keyless() {
return []byte{}, nil
}
// When SigVerifier is not initialized, return the policy's PublicKey only if
// it is valid PEM (e.g. "ec validate input" with publicKey in policy.yaml).
if p.checkOpts == nil || p.checkOpts.SigVerifier == nil {
return nil, errors.New("no check options or sig verifier configured")
if p.PublicKey == "" {
return []byte{}, nil
}
if !isPEM([]byte(p.PublicKey)) {
return nil, errors.New("public key is not in PEM format and signature verifier is not initialized")
}
return []byte(p.PublicKey), nil
}
pk, err := p.checkOpts.SigVerifier.PublicKey()
if err != nil {
Expand All @@ -108,6 +119,12 @@ func (p *policy) PublicKeyPEM() ([]byte, error) {
return cryptoutils.MarshalPublicKeyToPEM(pk)
}

// isPEM reports whether data contains at least one valid PEM block.
func isPEM(data []byte) bool {
block, _ := pem.Decode(data)
return block != nil
}

func (p *policy) CheckOpts() (*cosign.CheckOpts, error) {
if p.checkOpts == nil {
return nil, errors.New("no check options configured")
Expand Down
15 changes: 12 additions & 3 deletions internal/policy/policy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -526,11 +526,20 @@ func TestPublicKeyPEM(t *testing.T) {
expectedPublicKey: utils.TestPublicKey,
},
{
name: "checkOpts is nil",
// When checkOpts is nil but publicKey in spec is valid PEM, return it (e.g. "ec validate input").
name: "checkOpts is nil but publicKey in spec is PEM",
newPolicy: func(ctx context.Context) (Policy, error) {
return NewInertPolicy(ctx, fmt.Sprintf(`{"publicKey": "%s"}`, utils.TestPublicKey))
return NewInertPolicy(ctx, fmt.Sprintf(`{"publicKey": %s}`, utils.TestPublicKeyJSON))
},
err: "no check options or sig verifier configured",
expectedPublicKey: utils.TestPublicKey,
},
{
// When checkOpts is nil and publicKey is not PEM, return error to uphold method contract.
name: "checkOpts is nil and publicKey in spec is not PEM",
newPolicy: func(ctx context.Context) (Policy, error) {
return NewInertPolicy(ctx, `{"publicKey": "not-pem-key-ref-or-path"}`)
},
err: "public key is not in PEM format and signature verifier is not initialized",
},
{
name: "keyless",
Expand Down
Loading