Skip to content
Merged
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
12 changes: 9 additions & 3 deletions terraform/lambda-src/slack_alert/handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,11 @@ def service_display_name(event_source):
# ---------------------------------------------------------------------------
# Identity / resource extraction — GitHub OIDC attribution
# ---------------------------------------------------------------------------
def _strip_github_ids(repo):
"""Turn an immutable-subject owner/repo ('javaBin@95047/x@123') into 'javaBin/x'."""
return re.sub(r"@\d+", "", repo)


def parse_identity(detail):
"""Extract human-readable identity from CloudTrail userIdentity.

Expand All @@ -283,7 +288,8 @@ def parse_identity(detail):
- GitHubSHA: the commit SHA
- GitHubRepo: org/repo (e.g. javaBin/moresleep)
- GitHubRunID: the workflow run ID
The OIDC sub claim format: repo:javaBin/{name}:ref:refs/heads/{branch}
The OIDC sub claim format: repo:javaBin/{name}:ref:refs/heads/{branch}, or for repos
with immutable subjects repo:javaBin@{org_id}/{name}@{repo_id}:ref:refs/heads/{branch}
"""
identity = detail.get("userIdentity", {})
arn = identity.get("arn", "unknown")
Expand Down Expand Up @@ -319,7 +325,7 @@ def parse_identity(detail):
r"repo:([^:]+):ref:refs/(?:heads|tags)/(.+)", sub_claim
)
if sub_match:
ci_ctx["repo"] = sub_match.group(1)
ci_ctx["repo"] = _strip_github_ids(sub_match.group(1))
ci_ctx["ref"] = sub_match.group(2)

# Session tags from OIDC (if present in CloudTrail)
Expand All @@ -336,7 +342,7 @@ def parse_identity(detail):
r"repo:([^:]+):ref:refs/(?:heads|tags)/(.+)", session
)
if sub_match:
ci_ctx["repo"] = sub_match.group(1)
ci_ctx["repo"] = _strip_github_ids(sub_match.group(1))
ci_ctx["ref"] = sub_match.group(2)

# Parse enriched session name: {actor}-{sha8}-{run_id}
Expand Down
37 changes: 37 additions & 0 deletions terraform/lambda-src/tests/test_slack_alert_identity.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
"""Tests for slack_alert GitHub OIDC attribution — run: python3 -m unittest discover -s terraform/lambda-src/tests"""

import unittest

from test_slack_alert_ecs import FakeTable, load


def ci_detail(sub):
return {
"userIdentity": {
"type": "AssumedRole",
"arn": "arn:aws:sts::111111111111:assumed-role/javabin-ci-app-broker/someone-deadbeef-42",
"sessionContext": {"webIdFederationData": {"attributes": {"sub": sub}}},
}
}


class CiIdentityTests(unittest.TestCase):
def setUp(self):
self.mod = load(FakeTable())

def ci_context(self, sub):
_, is_ci, ctx = self.mod.parse_identity(ci_detail(sub))
self.assertTrue(is_ci)
return ctx

def test_legacy_subject(self):
ctx = self.ci_context("repo:javaBin/jz-watch:ref:refs/heads/main")
self.assertEqual((ctx["repo"], ctx["ref"]), ("javaBin/jz-watch", "main"))

def test_immutable_subject_strips_ids(self):
ctx = self.ci_context("repo:javaBin@95047/2027.javazone.no@1433986972:ref:refs/heads/main")
self.assertEqual((ctx["repo"], ctx["ref"]), ("javaBin/2027.javazone.no", "main"))


if __name__ == "__main__":
unittest.main()
15 changes: 12 additions & 3 deletions terraform/platform/iam/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,10 @@ resource "aws_iam_role" "ci_app_broker" {
"token.actions.githubusercontent.com:aud" = "sts.amazonaws.com"
}
StringLike = {
"token.actions.githubusercontent.com:sub" = "repo:${var.github_org}/*:*"
"token.actions.githubusercontent.com:sub" = [
"repo:${var.github_org}/*:*",
"repo:${var.github_org}@${var.github_org_id}/*:*",
]
"token.actions.githubusercontent.com:job_workflow_ref" = [
"${var.github_org}/platform/.github/workflows/tf-plan.yml@refs/heads/main",
"${var.github_org}/platform/.github/workflows/docker-build.yml@refs/heads/main",
Expand Down Expand Up @@ -773,7 +776,10 @@ resource "aws_iam_role" "ci_override_approver" {
"token.actions.githubusercontent.com:aud" = "sts.amazonaws.com"
}
StringLike = {
"token.actions.githubusercontent.com:sub" = "repo:${var.github_org}/*:*"
"token.actions.githubusercontent.com:sub" = [
"repo:${var.github_org}/*:*",
"repo:${var.github_org}@${var.github_org_id}/*:*",
]
# Pin to the approve-override workflow on main branch
"token.actions.githubusercontent.com:job_workflow_ref" = "${var.github_org}/platform/.github/workflows/approve-override.yml@refs/heads/main"
}
Expand Down Expand Up @@ -892,7 +898,10 @@ resource "aws_iam_role" "ci_apply_gate" {
"token.actions.githubusercontent.com:aud" = "sts.amazonaws.com"
}
StringLike = {
"token.actions.githubusercontent.com:sub" = "repo:${var.github_org}/*:*"
"token.actions.githubusercontent.com:sub" = [
"repo:${var.github_org}/*:*",
"repo:${var.github_org}@${var.github_org_id}/*:*",
]
"token.actions.githubusercontent.com:job_workflow_ref" = "${var.github_org}/platform/.github/workflows/tf-apply.yml@refs/heads/main"
}
}
Expand Down
6 changes: 6 additions & 0 deletions terraform/platform/iam/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ variable "github_org" {
default = "javaBin"
}

variable "github_org_id" {
description = "GitHub organization ID, used in immutable OIDC subjects (repo:<org>@<org_id>/<repo>@<repo_id>:...)"
type = string
default = "95047"
}

variable "apply_gate_role_arn" {
description = "ARN of the apply-gate Lambda role (for team role trust policy)"
type = string
Expand Down
Loading