From 9126b40b5bf7adf0429a81931c424de5b3c35425 Mon Sep 17 00:00:00 2001 From: Thierno Bah Date: Mon, 31 Aug 2026 23:32:32 +0100 Subject: [PATCH 1/4] test(action): add PR reporting proof Exercise the local Action with an exact published Rootform release and a synthetic same-repository architecture change. This proof branch is not intended to merge. --- .../workflows/pull-request-reporting-demo.yml | 42 ++++ .../e2e/pull-request-reporting/before/main.tf | 19 ++ .../pull-request-reporting/current/main.tf | 23 ++ .../dialects/aws/dialect.rf | 11 + .../dialects/aws/network/ec2.rf | 198 ++++++++++++++++++ .../dialects/aws/network/vpc.rf | 187 +++++++++++++++++ .../dialects/core/architecture/contexts.rf | 15 ++ .../dialects/core/dialect.rf | 3 + .../dialects/core/network/connectivity.rf | 24 +++ .../dialects/core/network/virtual-network.rf | 9 + 10 files changed, 531 insertions(+) create mode 100644 .github/workflows/pull-request-reporting-demo.yml create mode 100644 test/e2e/pull-request-reporting/before/main.tf create mode 100644 test/e2e/pull-request-reporting/current/main.tf create mode 100644 test/e2e/pull-request-reporting/dialects/aws/dialect.rf create mode 100644 test/e2e/pull-request-reporting/dialects/aws/network/ec2.rf create mode 100644 test/e2e/pull-request-reporting/dialects/aws/network/vpc.rf create mode 100644 test/e2e/pull-request-reporting/dialects/core/architecture/contexts.rf create mode 100644 test/e2e/pull-request-reporting/dialects/core/dialect.rf create mode 100644 test/e2e/pull-request-reporting/dialects/core/network/connectivity.rf create mode 100644 test/e2e/pull-request-reporting/dialects/core/network/virtual-network.rf diff --git a/.github/workflows/pull-request-reporting-demo.yml b/.github/workflows/pull-request-reporting-demo.yml new file mode 100644 index 0000000..17595cb --- /dev/null +++ b/.github/workflows/pull-request-reporting-demo.yml @@ -0,0 +1,42 @@ +name: pull request reporting demo + +on: + pull_request: + types: [opened, reopened, synchronize] + +permissions: + contents: read + pull-requests: write + +jobs: + architecture-review: + name: architecture review + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - name: Check out demo branch + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - name: Prepare exact demo dialects + shell: bash + run: | + set -euo pipefail + for project in before current; do + mkdir -p "test/e2e/pull-request-reporting/${project}/.rootform" + cp -R \ + test/e2e/pull-request-reporting/dialects \ + "test/e2e/pull-request-reporting/${project}/.rootform/dialects" + done + + - name: Run Rootform architecture review + uses: ./ + with: + artifact-name: rootform-pr-${{ github.event.pull_request.number }} + baseline-path: test/e2e/pull-request-reporting/before + fail-on-changes: "false" + fail-on-violations: "true" + github-token: ${{ secrets.ROOTFORM_RELEASES_READ_TOKEN }} + path: test/e2e/pull-request-reporting/current + pull-request-token: ${{ github.token }} + report-diff: "true" + version: 0.1.0-dev.2 diff --git a/test/e2e/pull-request-reporting/before/main.tf b/test/e2e/pull-request-reporting/before/main.tf new file mode 100644 index 0000000..381bb2d --- /dev/null +++ b/test/e2e/pull-request-reporting/before/main.tf @@ -0,0 +1,19 @@ +terraform { + required_version = ">= 1.14.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = "= 6.62.0" + } + } +} + +resource "aws_vpc" "main" { + cidr_block = "10.20.0.0/16" +} + +resource "aws_subnet" "application" { + vpc_id = aws_vpc.main.id + cidr_block = "10.20.1.0/24" +} diff --git a/test/e2e/pull-request-reporting/current/main.tf b/test/e2e/pull-request-reporting/current/main.tf new file mode 100644 index 0000000..a773a45 --- /dev/null +++ b/test/e2e/pull-request-reporting/current/main.tf @@ -0,0 +1,23 @@ +terraform { + required_version = ">= 1.14.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = "= 6.62.0" + } + } +} + +resource "aws_vpc" "main" { + cidr_block = "10.30.0.0/16" +} + +resource "aws_subnet" "public" { + vpc_id = aws_vpc.main.id + cidr_block = "10.30.1.0/24" +} + +resource "aws_internet_gateway" "main" { + vpc_id = aws_vpc.main.id +} diff --git a/test/e2e/pull-request-reporting/dialects/aws/dialect.rf b/test/e2e/pull-request-reporting/dialects/aws/dialect.rf new file mode 100644 index 0000000..e4c7635 --- /dev/null +++ b/test/e2e/pull-request-reporting/dialects/aws/dialect.rf @@ -0,0 +1,11 @@ +dialect "aws" { + version = "0.1.0" + + requires { + core = "0.1.0" + } + + provider "hashicorp/aws" { + version = "= 6.62.0" + } +} diff --git a/test/e2e/pull-request-reporting/dialects/aws/network/ec2.rf b/test/e2e/pull-request-reporting/dialects/aws/network/ec2.rf new file mode 100644 index 0000000..a8db464 --- /dev/null +++ b/test/e2e/pull-request-reporting/dialects/aws/network/ec2.rf @@ -0,0 +1,198 @@ +# Generated by scripts/generate-aws-dialect.ts. +concept "customer-gateway" { + kind = entity + description = "AWS VPN (Site-to-Site) customer gateway as a durable AWS architecture entity." +} + +concept "ec2-client-vpn-endpoint" { + kind = entity + description = "AWS VPN (Client) client VPN endpoint as a durable AWS architecture entity." +} + +concept "ec2-transit-gateway-multicast-domain" { + kind = scope + description = "AWS Transit Gateway transit gateway multicast domain as a durable AWS architecture scope." +} + +concept "ec2-transit-gateway-policy-table" { + kind = entity + description = "AWS Transit Gateway transit gateway policy table as a durable AWS architecture entity." +} + +concept "ec2-transit-gateway-route-table" { + kind = entity + description = "AWS Transit Gateway transit gateway route table as a durable AWS architecture entity." +} + +concept "egress-only-internet-gateway" { + kind = entity + description = "Amazon VPC egress-only internet gateway as a durable AWS architecture entity." +} + +concept "internet-gateway" { + kind = entity + description = "Amazon VPC internet gateway as a durable AWS architecture entity." +} + +concept "network-acl" { + kind = entity + description = "Amazon VPC network ACL as a durable AWS architecture entity." +} + +concept "route-table" { + kind = entity + description = "Amazon VPC route table as a durable AWS architecture entity." +} + +concept "security-group" { + kind = entity + description = "Amazon VPC security group as a durable AWS architecture entity." +} + +concept "transit-gateway" { + kind = entity + description = "An AWS Transit Gateway connecting multiple networks." +} + +concept "transit-gateway-attachment" { + kind = detail + description = "A network attachment contributing to an AWS Transit Gateway." +} + +concept "verifiedaccess-endpoint" { + kind = entity + description = "AWS Verified Access verified access endpoint as a durable AWS architecture entity." +} + +concept "verifiedaccess-group" { + kind = entity + description = "AWS Verified Access verified access group as a durable AWS architecture entity." +} + +concept "verifiedaccess-instance" { + kind = entity + description = "AWS Verified Access verified access instance as a durable AWS architecture entity." +} + +concept "vpc-endpoint-service" { + kind = entity + description = "Amazon VPC VPC endpoint service as a durable AWS architecture entity." +} + +concept "vpc-ipam-pool" { + kind = scope + description = "AWS VPC IPAM (IP Address Manager) ipam pool as a durable AWS architecture scope." +} + +concept "vpc-route-server-endpoint" { + kind = entity + description = "Amazon VPC VPC route server endpoint as a durable AWS architecture entity." +} + +rule "customer-gateway" { + match { + kind = "resource" + type = "aws_customer_gateway" + } + + as = concept.customer-gateway +} + +rule "ec2-client-vpn-endpoint" { + match { + kind = "resource" + type = "aws_ec2_client_vpn_endpoint" + } + + as = concept.ec2-client-vpn-endpoint +} + +rule "ec2-transit-gateway-multicast-domain" { + match { + kind = "resource" + type = "aws_ec2_transit_gateway_multicast_domain" + } + + as = concept.ec2-transit-gateway-multicast-domain +} + +rule "ec2-transit-gateway-policy-table" { + match { + kind = "resource" + type = "aws_ec2_transit_gateway_policy_table" + } + + as = concept.ec2-transit-gateway-policy-table +} + +rule "ec2-transit-gateway-route-table" { + match { + kind = "resource" + type = "aws_ec2_transit_gateway_route_table" + } + + as = concept.ec2-transit-gateway-route-table +} + +rule "egress-only-internet-gateway" { + match { + kind = "resource" + type = "aws_egress_only_internet_gateway" + } + + as = concept.egress-only-internet-gateway +} + +rule "verifiedaccess-endpoint" { + match { + kind = "resource" + type = "aws_verifiedaccess_endpoint" + } + + as = concept.verifiedaccess-endpoint +} + +rule "verifiedaccess-group" { + match { + kind = "resource" + type = "aws_verifiedaccess_group" + } + + as = concept.verifiedaccess-group +} + +rule "verifiedaccess-instance" { + match { + kind = "resource" + type = "aws_verifiedaccess_instance" + } + + as = concept.verifiedaccess-instance +} + +rule "vpc-endpoint-service" { + match { + kind = "resource" + type = "aws_vpc_endpoint_service" + } + + as = concept.vpc-endpoint-service +} + +rule "vpc-ipam-pool" { + match { + kind = "resource" + type = "aws_vpc_ipam_pool" + } + + as = concept.vpc-ipam-pool +} + +rule "vpc-route-server-endpoint" { + match { + kind = "resource" + type = "aws_vpc_route_server_endpoint" + } + + as = concept.vpc-route-server-endpoint +} diff --git a/test/e2e/pull-request-reporting/dialects/aws/network/vpc.rf b/test/e2e/pull-request-reporting/dialects/aws/network/vpc.rf new file mode 100644 index 0000000..bdd5c50 --- /dev/null +++ b/test/e2e/pull-request-reporting/dialects/aws/network/vpc.rf @@ -0,0 +1,187 @@ +rule "vpc" { + match { + kind = "resource" + type = "aws_vpc" + } + + as = concept.core.virtual-network +} + +rule "subnet" { + match { + kind = "resource" + type = "aws_subnet" + } + + as = concept.core.subnet + + context { + as = context.core.network + to = concept.core.virtual-network + via = source.vpc_id + } +} + +rule "vpc-endpoint" { + match { + kind = "resource" + type = "aws_vpc_endpoint" + } + + as = concept.core.private-endpoint + + context { + as = context.core.network + to = concept.core.virtual-network + via = source.vpc_id + } +} + +rule "ec2-transit-gateway" { + match { + kind = "resource" + type = "aws_ec2_transit_gateway" + } + + as = concept.transit-gateway +} + +rule "ec2-transit-gateway-vpc-attachment" { + match { + kind = "resource" + type = "aws_ec2_transit_gateway_vpc_attachment" + } + + as = concept.transit-gateway-attachment + + contribution { + to = concept.transit-gateway + via = source.transit_gateway_id + } + + context { + as = context.core.network + to = concept.core.virtual-network + via = source.vpc_id + } +} + +rule "route-table" { + match { + kind = "resource" + type = "aws_route_table" + } + + as = concept.route-table + + context { + as = context.core.network + to = concept.core.virtual-network + via = source.vpc_id + } +} + +rule "security-group" { + match { + kind = "resource" + type = "aws_security_group" + } + + as = concept.security-group + + context { + as = context.core.network + to = concept.core.virtual-network + via = source.vpc_id + } +} + +rule "network-acl" { + match { + kind = "resource" + type = "aws_network_acl" + } + + as = concept.network-acl + + context { + as = context.core.network + to = concept.core.virtual-network + via = source.vpc_id + } +} + +rule "internet-gateway" { + match { + kind = "resource" + type = "aws_internet_gateway" + } + + as = concept.internet-gateway + + context { + as = context.core.network + to = concept.core.virtual-network + via = source.vpc_id + } +} + +rule "nat-gateway" { + match { + kind = "resource" + type = "aws_nat_gateway" + } + + as = concept.core.managed-nat + + context { + as = context.core.network + to = concept.core.subnet + via = source.subnet_id + } +} + +rule "vpn-gateway" { + match { + kind = "resource" + type = "aws_vpn_gateway" + } + + as = concept.core.vpn-gateway + + context { + as = context.core.network + to = concept.core.virtual-network + via = source.vpc_id + } +} + +rule "vpc-peering-connection" { + match { + kind = "resource" + type = "aws_vpc_peering_connection" + } + + as = concept.core.network-peering +} + +rule "vpn-connection" { + match { + kind = "resource" + type = "aws_vpn_connection" + } + + as = concept.core.vpn-connection + + context { + as = context.core.network + to = concept.core.vpn-gateway + via = source.vpn_gateway_id + } + + context { + as = context.core.network + to = concept.transit-gateway + via = source.transit_gateway_id + } +} diff --git a/test/e2e/pull-request-reporting/dialects/core/architecture/contexts.rf b/test/e2e/pull-request-reporting/dialects/core/architecture/contexts.rf new file mode 100644 index 0000000..b36e680 --- /dev/null +++ b/test/e2e/pull-request-reporting/dialects/core/architecture/contexts.rf @@ -0,0 +1,15 @@ +context "network" { + description = "Network placement or containment." +} + +context "runtime" { + description = "Runtime placement or execution scope." +} + +context "ownership" { + description = "Administrative or lifecycle ownership." +} + +context "geography" { + description = "Geographic placement." +} diff --git a/test/e2e/pull-request-reporting/dialects/core/dialect.rf b/test/e2e/pull-request-reporting/dialects/core/dialect.rf new file mode 100644 index 0000000..e49fa84 --- /dev/null +++ b/test/e2e/pull-request-reporting/dialects/core/dialect.rf @@ -0,0 +1,3 @@ +dialect "core" { + version = "0.1.0" +} diff --git a/test/e2e/pull-request-reporting/dialects/core/network/connectivity.rf b/test/e2e/pull-request-reporting/dialects/core/network/connectivity.rf new file mode 100644 index 0000000..0de3cd1 --- /dev/null +++ b/test/e2e/pull-request-reporting/dialects/core/network/connectivity.rf @@ -0,0 +1,24 @@ +concept "managed-nat" { + kind = entity + description = "A managed network address translation service." +} + +concept "network-peering" { + kind = entity + description = "A direct private connectivity agreement between virtual networks." +} + +concept "private-endpoint" { + kind = entity + description = "A private endpoint exposing a service inside a virtual network." +} + +concept "vpn-gateway" { + kind = entity + description = "A managed gateway terminating virtual private network connections." +} + +concept "vpn-connection" { + kind = entity + description = "A virtual private network connection between network endpoints." +} diff --git a/test/e2e/pull-request-reporting/dialects/core/network/virtual-network.rf b/test/e2e/pull-request-reporting/dialects/core/network/virtual-network.rf new file mode 100644 index 0000000..ce73cd0 --- /dev/null +++ b/test/e2e/pull-request-reporting/dialects/core/network/virtual-network.rf @@ -0,0 +1,9 @@ +concept "virtual-network" { + kind = scope + description = "A virtual network that provides connectivity and isolation." +} + +concept "subnet" { + kind = scope + description = "A subnet that segments a virtual network." +} From c37565b0170c9d7c682b24998f04e247e556be0e Mon Sep 17 00:00:00 2001 From: Thierno Bah Date: Mon, 31 Aug 2026 23:39:25 +0100 Subject: [PATCH 2/4] test(action): prove unchanged report --- test/e2e/pull-request-reporting/current/main.tf | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/test/e2e/pull-request-reporting/current/main.tf b/test/e2e/pull-request-reporting/current/main.tf index a773a45..381bb2d 100644 --- a/test/e2e/pull-request-reporting/current/main.tf +++ b/test/e2e/pull-request-reporting/current/main.tf @@ -10,14 +10,10 @@ terraform { } resource "aws_vpc" "main" { - cidr_block = "10.30.0.0/16" + cidr_block = "10.20.0.0/16" } -resource "aws_subnet" "public" { +resource "aws_subnet" "application" { vpc_id = aws_vpc.main.id - cidr_block = "10.30.1.0/24" -} - -resource "aws_internet_gateway" "main" { - vpc_id = aws_vpc.main.id + cidr_block = "10.20.1.0/24" } From c3548d2bb51d80e2168d90f211e047575c378461 Mon Sep 17 00:00:00 2001 From: Thierno Bah Date: Mon, 31 Aug 2026 23:41:46 +0100 Subject: [PATCH 3/4] test(action): recapture changed report --- test/e2e/pull-request-reporting/current/main.tf | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/test/e2e/pull-request-reporting/current/main.tf b/test/e2e/pull-request-reporting/current/main.tf index 381bb2d..a773a45 100644 --- a/test/e2e/pull-request-reporting/current/main.tf +++ b/test/e2e/pull-request-reporting/current/main.tf @@ -10,10 +10,14 @@ terraform { } resource "aws_vpc" "main" { - cidr_block = "10.20.0.0/16" + cidr_block = "10.30.0.0/16" } -resource "aws_subnet" "application" { +resource "aws_subnet" "public" { vpc_id = aws_vpc.main.id - cidr_block = "10.20.1.0/24" + cidr_block = "10.30.1.0/24" +} + +resource "aws_internet_gateway" "main" { + vpc_id = aws_vpc.main.id } From 0313c1d6674c2e3da09f8cf2ba4a8e5e771030d5 Mon Sep 17 00:00:00 2001 From: Thierno Bah Date: Mon, 31 Aug 2026 23:44:18 +0100 Subject: [PATCH 4/4] test(action): leave proof comment clean --- test/e2e/pull-request-reporting/current/main.tf | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/test/e2e/pull-request-reporting/current/main.tf b/test/e2e/pull-request-reporting/current/main.tf index a773a45..381bb2d 100644 --- a/test/e2e/pull-request-reporting/current/main.tf +++ b/test/e2e/pull-request-reporting/current/main.tf @@ -10,14 +10,10 @@ terraform { } resource "aws_vpc" "main" { - cidr_block = "10.30.0.0/16" + cidr_block = "10.20.0.0/16" } -resource "aws_subnet" "public" { +resource "aws_subnet" "application" { vpc_id = aws_vpc.main.id - cidr_block = "10.30.1.0/24" -} - -resource "aws_internet_gateway" "main" { - vpc_id = aws_vpc.main.id + cidr_block = "10.20.1.0/24" }