Skip to content

Add automated namespace approval workflow for spec PRs - #44085

Merged
Mike Harder (mikeharder) merged 24 commits into
Azure:mainfrom
samvaity:namespace-approval
Jul 8, 2026
Merged

Mike Harder (mikeharder) merged 24 commits into
Azure:mainfrom
samvaity:namespace-approval

Conversation

@samvaity

@samvaity Sameeksha Vaity (samvaity) commented Jun 18, 2026 •

Copy link
Copy Markdown
Member

Summary

Adds automated namespace approval for SDK library names directly on spec PRs. When a service team adds or modifies namespace/package-name configuration in tspconfig.yaml, authorized architects must approve before the PR can merge.

What this replaces

Previously, namespace approval was tracked via email to azsdkarch-help@microsoft.com and manual triage. This automates it as a merge gate directly in the spec PR workflow.

How it works

  1. Detection — When a PR modifies tspconfig.yaml, the workflow extracts namespaces using @azure-tools/typespec-metadata emitter and applies <lang>-namespace-pending labels
  2. Approval — Authorized architects apply <lang>-namespace-approved labels (or namespace-approved-all for mgmt plane)
  3. Status check — A required check blocks merge until all pending namespaces are approved
  4. Reset — If a namespace value changes after approval, that language resets to pending

Testing POC

Tested end-to-end on fork PRs with real tspconfig.yaml changes:

Scenario Fork PR Result
Data-plane — multi-language detection samvaity/azure-rest-api-specs#2 ✅ 4 languages detected (dotnet, java, python, typescript), pending labels applied, bot comment posted with namespace table
Data-plane — per-language approval samvaity/azure-rest-api-specs#2 ✅ Each <lang>-namespace-approved label validated against approver list, bot comment updated per approval
ARM/mgmt — detection & type classification samvaity/azure-rest-api-specs#3 ✅ Management plane detected, Mgmt label applied, correct approver list shown
ARM/mgmt — namespace-approved-all shortcut samvaity/azure-rest-api-specs#3 ✅ Single label approves all pending languages at once, status check passes
Approval reset on namespace change samvaity/azure-rest-api-specs#2 ✅ On synchronize event, approved labels removed for changed namespaces
Unauthorized approver rejection samvaity/azure-rest-api-specs#2 ✅ Label auto-removed, comment posted explaining who is authorized
No tspconfig changes — skip samvaity/azure-rest-api-specs#2 ✅ Workflow exits early, no labels or comments
YAML fallback (emitter unavailable) samvaity/azure-rest-api-specs#2 ✅ Falls back to parsing tspconfig.yaml options directly

Related

@github-actions

github-actions Bot commented Jun 18, 2026 •

Copy link
Copy Markdown

Next Steps to Merge

Next steps that must be taken to merge this PR:
  • ❌ The required check named Protected Files has failed. Refer to the check in the PR's 'Checks' tab for details on how to fix it and consult the aka.ms/ci-fix guide


Comment generated by summarize-checks workflow run.

@samvaity
Sameeksha Vaity (samvaity) force-pushed the namespace-approval branch 2 times, most recently from bc266b3 to 59c20cf Compare June 18, 2026 23:19
GitHub Actions workflow that validates namespace changes on spec PRs:
- Detects namespaces from tspconfig.yaml using @azure-tools/typespec-metadata emitter
- Applies per-language namespace-pending labels for architect review
- Blocks merge until authorized architects approve via namespace-approved labels
- Supports namespace-approved-all shortcut for management plane
- Resets approval when namespace values change
- Uses repo conventions: ESM modules in src/, actions/checkout@v6,
  actions/github-script@v8, ubuntu-24.04, install-deps-github-script
- Reuses existing Mgmt and data-plane labels

Files added:
- .github/workflows/namespace-approval.yml
- .github/workflows/src/namespace-approval/detect-namespaces.js
- .github/workflows/src/namespace-approval/validate-approval.js
- .github/workflows/src/namespace-approval/status-check.js
- .github/namespace-approvers.yml
- .github/NAMESPACE-REVIEW-PROCESS.md

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add unlabeled handler: re-applies pending labels if removed by
  unauthorized user (non-approver, non-bot)
- Allow authorized approvers and bots (github-actions, azure-sdk)
  to remove namespace labels
- Remove C++/Rust from approvers config and process docs (no
  emitter config exists for these in tspconfig.yaml)
- Update workflow to trigger on unlabeled events
- Add 33 unit tests for validate-approval, status-check, and validate-format
- Add validate-format.js module with per-language regex validation
- Add namespace-format-rules.yml config (Arthur's regex patterns)
- Integrate format validation into detect-namespaces.js bot comment
- All ESLint and Prettier checks passing

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Remove try/catch + core.setFailed pattern, let exceptions bubble up
  (detect-namespaces.js, post-results.js, validate-approval.js)
- Use extractInputs() helper in validate-approval.js for consistent
  context extraction with logging and GitHub API hooks
- Add tspconfig() filter to shared changed-files.js helper
- Remove RUNNER_TEMP fallbacks (always set in CI)
- Remove unnecessary JSDoc type casts on already-typed artifacts
- Remove tmpdir import (no longer needed)
- Throw error when no approvers configured instead of silent TBD fallback
- Throw error when no namespace-results artifact found instead of null
- Remove null-check anti-patterns in postResults caller
- Fix prettier formatting on NAMESPACE-REVIEW-PROCESS.md
- Update tests for new extractInputs usage and removed setFailed calls

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…g filter

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ming, docs

- Extract ApproversConfig typedef and loadApproversConfig() into shared approvers.js (#2)
- Use github.paginate() for listComments in validate-approval.js (#3)
- Reorder label operations: add approved before removing pending (#4)
- Add comment explaining mgmt-only format validation scoping (#5)
- Change loadFormatRules() from sync readFileSync to async readFile (#7)
- Use owner/repo from extractInputs() consistently, remove prNumber alias
- Document security model and format validation scope in NAMESPACE-REVIEW-PROCESS.md (#1, #5)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…vents

When multiple per-language labels are applied in quick succession, each
triggers a separate labeled event. Check if the approval comment already
exists before posting to avoid duplicates.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Label rename: <lang>-namespace-approved/pending to namespace-<lang>-approved/pending
to align with team consensus (namespace-<lang>-approved format).

GitHub @Handles: Approver column in bot comment now uses @username format
to tag language architects directly on the main repo.

NSTM integration: Added RequiredLabelRule in labelling.js so namespace-review-required
triggers a blocker in the Next Steps to Merge comment, pointing users to the
detailed namespace review table.

Updated all source files, tests, and NAMESPACE-REVIEW-PROCESS.md documentation.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…tion

- Extract removeLabelIfPresent() into labels.js shared module
- Remove inline try/catch duplicates in validate-approval.js
- Remove createLabel calls - labels should be pre-created on the repo
- Add clarifying comments on two-step plane detection logic

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@mikeharder
Mike Harder (mikeharder) merged commit 72d8d2a into Azure:main Jul 8, 2026
51 of 53 checks passed
Praveen Kuttappan (praveenkuttappan) pushed a commit to Azure/azure-sdk that referenced this pull request Jul 9, 2026
The management plane namespace review process is being automated
via the namespace approval workflow in azure-rest-api-specs
(PR Azure/azure-rest-api-specs#44085).
GSLeonardo (GSLeonardo) pushed a commit that referenced this pull request Jul 13, 2026
* Add automated namespace approval workflow for spec PRs

GitHub Actions workflow that validates namespace changes on spec PRs:
- Detects namespaces from tspconfig.yaml using @azure-tools/typespec-metadata emitter
- Applies per-language namespace-pending labels for architect review
- Blocks merge until authorized architects approve via namespace-approved labels
- Supports namespace-approved-all shortcut for management plane
- Resets approval when namespace values change
- Uses repo conventions: ESM modules in src/, actions/checkout@v6,
  actions/github-script@v8, ubuntu-24.04, install-deps-github-script
- Reuses existing Mgmt and data-plane labels

Files added:
- .github/workflows/namespace-approval.yml
- .github/workflows/src/namespace-approval/detect-namespaces.js
- .github/workflows/src/namespace-approval/validate-approval.js
- .github/workflows/src/namespace-approval/status-check.js
- .github/namespace-approvers.yml
- .github/NAMESPACE-REVIEW-PROCESS.md

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Address review feedback: unlabeled guard, remove C++/Rust

- Add unlabeled handler: re-applies pending labels if removed by
  unauthorized user (non-approver, non-bot)
- Allow authorized approvers and bots (github-actions, azure-sdk)
  to remove namespace labels
- Remove C++/Rust from approvers config and process docs (no
  emitter config exists for these in tspconfig.yaml)
- Update workflow to trigger on unlabeled events

* Add unit tests and namespace format validation

- Add 33 unit tests for validate-approval, status-check, and validate-format
- Add validate-format.js module with per-language regex validation
- Add namespace-format-rules.yml config (Arthur's regex patterns)
- Integrate format validation into detect-namespaces.js bot comment
- All ESLint and Prettier checks passing

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Address review: split workflow, use repo helpers, add zod schema

- Split namespace-approval.yml into code + status workflows
  (namespace-approval-code.yaml / namespace-approval-status.yaml)
  to support fork PRs (read-only vs write permissions)
- Use repo helpers: getChangedFiles(), execNpmExec(), extractInputs(),
  commentOrUpdate(), async fs APIs
- Add zod schema for typespec-metadata.json validation
- Write emitter output to RUNNER_TEMP instead of clone dir
- Drop YAML fallback codepath (emitter-only)
- Move NAMESPACE-REVIEW-PROCESS.md into src/namespace-approval/
- Create post-results.js for status workflow (artifact-based)
- Add reopened + edited trigger types, fetch-depth: 2

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix CI: prettier formatting and cspell word

- Run prettier --write on 6 files to match repo style
- Add cspell:ignore for hex color fbbf24 in post-results.js
- Protected Files check requires maintainer approval (expected)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix: use sparse-checkout add instead of git checkout for hydration

git checkout HEAD -- <path> fails when sparse-checkout cone mode is
active and the path is outside the cone. Use git sparse-checkout add
to expand the cone, which materializes the files properly.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Parse tspconfig.yaml directly, add commit status gate, fix plane detection

- Replace tsp compile with direct YAML parsing (works with sparse checkout)
- Add module/crate-name parsing for Go/Rust emitters
- Create commit status (Namespace Approval) as single PR merge gate
- Fix plane detection: linter extends overrides path-based guess
- Update docs and bot comment to reflect YAML parsing approach

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Split status workflow into separate files following repo convention

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix: deduplicate job name in code workflow to match repo convention

* Address review: add else fallback in status check, fix check name in docs

* Add Namespace Approval to summarize-checks for Next Steps to Merge

* Add Java Maven artifact dual namespace, selective reset, lint and type fixes

- Extract Maven artifact name from Java emitter-output-dir in tspconfig
- Show both package and artifact rows in namespace review table
- Update validate-approval regex to approve all rows per language (gi flag)
- Implement selective per-language namespace reset on synchronize
- Add parseCommentTable for comparing old vs new namespaces
- Add unit tests: detect-namespaces (5), post-results (16)
- Fix TypeScript type errors: use shared mocks, double-cast args() pattern
- Fix eslint: type-annotate Map declarations, callback params
- Fix spellcheck: replace jsquire with approver-a in tests
- Update NAMESPACE-REVIEW-PROCESS.md with selective reset docs

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix namespace approval TS type errors

* Address review feedback: error handling, shared helpers, and cleanup

- Remove try/catch + core.setFailed pattern, let exceptions bubble up
  (detect-namespaces.js, post-results.js, validate-approval.js)
- Use extractInputs() helper in validate-approval.js for consistent
  context extraction with logging and GitHub API hooks
- Add tspconfig() filter to shared changed-files.js helper
- Remove RUNNER_TEMP fallbacks (always set in CI)
- Remove unnecessary JSDoc type casts on already-typed artifacts
- Remove tmpdir import (no longer needed)
- Throw error when no approvers configured instead of silent TBD fallback
- Throw error when no namespace-results artifact found instead of null
- Remove null-check anti-patterns in postResults caller
- Fix prettier formatting on NAMESPACE-REVIEW-PROCESS.md
- Update tests for new extractInputs usage and removed setFailed calls

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix CodeQL ReDoS alert: replace regex with string methods in tspconfig filter

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add coverage test for tspconfig filter in changed-files

* Fix namespace-approval TypeScript null and env typing errors

* Address review issues: shared approvers, pagination, async format, timing, docs

- Extract ApproversConfig typedef and loadApproversConfig() into shared approvers.js (#2)
- Use github.paginate() for listComments in validate-approval.js (#3)
- Reorder label operations: add approved before removing pending (#4)
- Add comment explaining mgmt-only format validation scoping (#5)
- Change loadFormatRules() from sync readFileSync to async readFile (#7)
- Use owner/repo from extractInputs() consistently, remove prNumber alias
- Document security model and format validation scope in NAMESPACE-REVIEW-PROCESS.md (#1, #5)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Prevent duplicate 'Namespace Approved' comments on concurrent label events

When multiple per-language labels are applied in quick succession, each
triggers a separate labeled event. Check if the approval comment already
exists before posting to avoid duplicates.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Rename labels to namespace-<lang>-*, add @Handles, integrate with NSTM

Label rename: <lang>-namespace-approved/pending to namespace-<lang>-approved/pending
to align with team consensus (namespace-<lang>-approved format).

GitHub @Handles: Approver column in bot comment now uses @username format
to tag language architects directly on the main repo.

NSTM integration: Added RequiredLabelRule in labelling.js so namespace-review-required
triggers a blocker in the Next Steps to Merge comment, pointing users to the
detailed namespace review table.

Updated all source files, tests, and NAMESPACE-REVIEW-PROCESS.md documentation.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Extract shared labels helper, remove createLabel, clarify plane detection

- Extract removeLabelIfPresent() into labels.js shared module
- Remove inline try/catch duplicates in validate-approval.js
- Remove createLabel calls - labels should be pre-created on the repo
- Add clarifying comments on two-step plane detection logic

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix NSTM: clarify namespace-approved-all is mgmt-plane only

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* changed-files helper cleanup

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Mike Harder <mharder@microsoft.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants