Skip to content

Commit

Permalink
Add more Buildkite tests
Browse files Browse the repository at this point in the history
Signed-off-by: Samuel Cochran <sj26@sj26.com>
  • Loading branch information
sj26 committed Jan 17, 2023
1 parent ab268bc commit 0029135
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 8 deletions.
3 changes: 3 additions & 0 deletions pkg/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,9 @@ func Test_issuerToChallengeClaim(t *testing.T) {
if claim := issuerToChallengeClaim(IssuerTypeURI); claim != "sub" {
t.Fatalf("expected sub subject claim for URI issuer, got %s", claim)
}
if claim := issuerToChallengeClaim(IssuerTypeBuildkiteJob); claim != "sub" {
t.Fatalf("expected sub subject claim for Buildkite issuer, got %s", claim)
}
if claim := issuerToChallengeClaim(IssuerTypeGithubWorkflow); claim != "sub" {
t.Fatalf("expected sub subject claim for GitHub issuer, got %s", claim)
}
Expand Down
114 changes: 106 additions & 8 deletions pkg/server/grpc_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ func TestGetConfiguration(t *testing.T) {
_, uriIssuer := newOIDCIssuer(t)
_, usernameIssuer := newOIDCIssuer(t)
_, k8sIssuer := newOIDCIssuer(t)
_, buildkiteIssuer := newOIDCIssuer(t)
_, gitHubIssuer := newOIDCIssuer(t)

issuerDomain, err := url.Parse(usernameIssuer)
Expand Down Expand Up @@ -210,22 +211,28 @@ func TestGetConfiguration(t *testing.T) {
"SubjectDomain": %q,
"Type": "username"
},
%q: {
"IssuerURL": %q,
"ClientID": "sigstore",
"Type": "buildkite-job"
},
%q: {
"IssuerURL": %q,
"ClientID": "sigstore",
"Type": "github-workflow"
}
},
"MetaIssuers": {
%q: {
"ClientID": "sigstore",
"Type": "kubernetes"
}
}
"MetaIssuers": {
%q: {
"ClientID": "sigstore",
"Type": "kubernetes"
}
}
}`, spiffeIssuer, spiffeIssuer,
uriIssuer, uriIssuer, uriIssuer,
emailIssuer, emailIssuer,
usernameIssuer, usernameIssuer, issuerDomain.Hostname(),
buildkiteIssuer, buildkiteIssuer,
gitHubIssuer, gitHubIssuer,
k8sIssuer)))
if err != nil {
Expand All @@ -247,13 +254,14 @@ func TestGetConfiguration(t *testing.T) {
t.Fatal("GetConfiguration failed", err)
}

if len(config.Issuers) != 6 {
t.Fatalf("expected 6 issuers, got %v", len(config.Issuers))
if len(config.Issuers) != 7 {
t.Fatalf("expected 7 issuers, got %v", len(config.Issuers))
}

expectedIssuers := map[string]bool{
emailIssuer: true, spiffeIssuer: true, uriIssuer: true,
usernameIssuer: true, k8sIssuer: true, gitHubIssuer: true,
buildkiteIssuer: true,
}
for _, iss := range config.Issuers {
var issURL string
Expand Down Expand Up @@ -679,6 +687,96 @@ func TestAPIWithKubernetes(t *testing.T) {
}
}

// buildkiteClaims holds the additional JWT claims for Buildkite OIDC tokens
type buildkiteClaims struct {
OrganizationSlug string `json:"organization_slug"`
PipelineSlug string `json:"pipeline_slug"`
}

// Tests API for Buildkite subject types
func TestAPIWithBuildkite(t *testing.T) {
buildkiteSigner, buildkiteIssuer := newOIDCIssuer(t)

// Create a FulcioConfig that supports these issuers.
cfg, err := config.Read([]byte(fmt.Sprintf(`{
"OIDCIssuers": {
%q: {
"IssuerURL": %q,
"ClientID": "sigstore",
"Type": "buildkite-job"
}
}
}`, buildkiteIssuer, buildkiteIssuer)))
if err != nil {
t.Fatalf("config.Read() = %v", err)
}

claims := buildkiteClaims{
OrganizationSlug: "acme-inc",
PipelineSlug: "bash-example",
}
buildkiteSubject := fmt.Sprintf("organization:%s:pipeline:%s:ref:refs/heads/main:commit:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:step:build", claims.OrganizationSlug, claims.PipelineSlug)

// Create an OIDC token using this issuer's signer.
tok, err := jwt.Signed(buildkiteSigner).Claims(jwt.Claims{
Issuer: buildkiteIssuer,
IssuedAt: jwt.NewNumericDate(time.Now()),
Expiry: jwt.NewNumericDate(time.Now().Add(30 * time.Minute)),
Subject: buildkiteSubject,
Audience: jwt.Audience{"sigstore"},
}).Claims(&claims).CompactSerialize()
if err != nil {
t.Fatalf("CompactSerialize() = %v", err)
}

ctClient, eca := createCA(cfg, t)
ctx := context.Background()
server, conn := setupGRPCForTest(ctx, t, cfg, ctClient, eca)
defer func() {
server.Stop()
conn.Close()
}()

client := protobuf.NewCAClient(conn)

pubBytes, proof := generateKeyAndProof(buildkiteSubject, t)

// Hit the API to have it sign our certificate.
resp, err := client.CreateSigningCertificate(ctx, &protobuf.CreateSigningCertificateRequest{
Credentials: &protobuf.Credentials{
Credentials: &protobuf.Credentials_OidcIdentityToken{
OidcIdentityToken: tok,
},
},
Key: &protobuf.CreateSigningCertificateRequest_PublicKeyRequest{
PublicKeyRequest: &protobuf.PublicKeyRequest{
PublicKey: &protobuf.PublicKey{
Content: pubBytes,
},
ProofOfPossession: proof,
},
},
})
if err != nil {
t.Fatalf("SigningCert() = %v", err)
}

leafCert := verifyResponse(resp, eca, buildkiteIssuer, t)

// Expect URI values
if len(leafCert.URIs) != 1 {
t.Fatalf("unexpected length of leaf certificate URIs, expected 1, got %d", len(leafCert.URIs))
}
buildkiteURL := fmt.Sprintf("https://buildkite.com/%s/%s", claims.OrganizationSlug, claims.PipelineSlug)
buildkiteURI, err := url.Parse(buildkiteURL)
if err != nil {
t.Fatalf("failed to parse subject URI")
}
if *leafCert.URIs[0] != *buildkiteURI {
t.Fatalf("URIs do not match: Expected %v, got %v", buildkiteURI, leafCert.URIs[0])
}
}

// githubClaims holds the additional JWT claims for GitHub OIDC tokens
type githubClaims struct {
JobWorkflowRef string `json:"job_workflow_ref"`
Expand Down

0 comments on commit 0029135

Please sign in to comment.