Skip to content

Commit 799484f

Browse files
authored
feat(foundry): add shared Foundry access module (#10845)
* feat(foundry): add shared Foundry access module Establish github.com/azure/azure-dev/cli/shared/foundry under cli/shared/foundry with shared project data-plane RBAC readiness (access) and portable typed errors (ferrors) (#9834). * fix(foundry): tighten scope and 409 conflict checks in access helpers * fix(foundry): scope build-test permissions and reject dot scope segments
1 parent 9d2d025 commit 799484f

16 files changed

Lines changed: 2204 additions & 0 deletions

File tree

‎.github/CODEOWNERS‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
/.vscode/cspell-github-user-aliases.txt @Azure/azure-dev-core @JerryYangKai @Siglud @XiaofuHuang @Yimin-Jin @achauhan-scc @anchenyi @aprilk-ms @chienyuanchang @davidm00 @eriolchan @glharper @hizixin @huimiu @hund030 @kingernupur @lc48t @m5i-work @m7md7sien @omkarmore83 @saanikaguptamicrosoft @sakoll @shrutiyer @smulumbi @sujit-kamireddy @therealjohn @trangevi @v1212 @valangar @wanglliwang @yungshinlintw
2020

2121
# ── CLI extensions (AI) ──────────────────────────────────────────────────────
22+
/cli/shared/foundry/ @Azure/azure-dev-core @glharper @trangevi @therealjohn @huimiu @eriolchan @hund030 @m5i-work @v1212 @JerryYangKai @Siglud @Yimin-Jin
2223
/cli/azd/extensions/ai-non-interactive.md @Azure/azure-dev-core @glharper @trangevi @therealjohn @huimiu @eriolchan @hund030 @m5i-work @v1212 @JerryYangKai @Siglud @Yimin-Jin
2324
/cli/azd/extensions/azure.ai.agents/ @Azure/azure-dev-core @glharper @trangevi @therealjohn @huimiu @eriolchan @hund030 @m5i-work @v1212 @JerryYangKai @Siglud @Yimin-Jin
2425
/cli/azd/test/functional/ai_agents/ @Azure/azure-dev-core @glharper @trangevi @therealjohn @huimiu @eriolchan @hund030 @m5i-work @v1212 @JerryYangKai @Siglud @Yimin-Jin
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
name: shared-foundry-ci
2+
3+
on:
4+
pull_request:
5+
paths:
6+
- "cli/shared/**"
7+
- ".github/workflows/shared-foundry.yml"
8+
branches: [main]
9+
push:
10+
branches: [main]
11+
tags: ["cli/shared/foundry/v*"]
12+
paths:
13+
- "cli/shared/**"
14+
- ".github/workflows/shared-foundry.yml"
15+
workflow_dispatch:
16+
17+
concurrency:
18+
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
19+
cancel-in-progress: true
20+
21+
permissions:
22+
contents: read
23+
pull-requests: write
24+
25+
jobs:
26+
lint:
27+
uses: ./.github/workflows/lint-go.yml
28+
with:
29+
working-directory: cli/shared/foundry
30+
go-version-file: cli/shared/foundry/go.mod
31+
32+
build-test:
33+
permissions:
34+
contents: read
35+
strategy:
36+
matrix:
37+
os: [ubuntu-latest, windows-latest]
38+
runs-on: ${{ matrix.os }}
39+
defaults:
40+
run:
41+
working-directory: cli/shared/foundry
42+
env:
43+
GOWORK: "off"
44+
steps:
45+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
46+
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
47+
with:
48+
go-version-file: cli/shared/foundry/go.mod
49+
cache-dependency-path: cli/shared/foundry/go.sum
50+
- run: go mod download
51+
- run: go mod verify
52+
- run: python eng/check-boundaries.py
53+
- run: go build ./...
54+
- run: go test ./... -count=1 -cover
55+
- run: go vet ./...
56+
- name: Race tests
57+
if: runner.os == 'Linux'
58+
run: go test -race ./... -count=1
59+
- name: Setup Node for cspell
60+
if: runner.os == 'Linux'
61+
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
62+
with:
63+
node-version: "20"
64+
- name: Install cspell
65+
if: runner.os == 'Linux'
66+
run: npm install -g cspell@8.13.1
67+
- name: Spelling
68+
if: runner.os == 'Linux'
69+
working-directory: .
70+
run: cspell lint "cli/shared/**/*.go" "cli/shared/**/*.md" --config cli/shared/foundry/cspell.yaml --no-progress

‎cli/shared/README.md‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Shared CLI modules
2+
3+
`cli/shared/` contains independently versioned Go modules reused by two or more
4+
extensions. They are source/build dependencies compiled into extension binaries,
5+
not installable azd extensions, runtime providers, or gRPC services. Do not add
6+
`extension.yaml` files or extension registry entries for these libraries.
7+
8+
Each child module owns its `go.mod`, dependency versions, tests, compatibility
9+
policy, release notes, and release tags. Releases are independent of azd core
10+
and of extension binary artifacts. A nested module uses its directory prefix in
11+
tags: `cli/shared/foundry/v0.1.0`, not `v0.1.0` or an `azd-ext-*` binary tag.
12+
Follow Go semantic import versioning for v2 and subsequent major versions.
13+
14+
Shared modules must not import an extension's `internal/` packages. Dependencies
15+
on azd core must be deliberate and documented, and must not defeat independent
16+
release. The Foundry module specifically forbids a core-module dependency.
17+
Host SDK/gRPC adaptation and product-specific command policy belong in consumers.
18+
19+
Adding a new child module under `cli/shared/` requires at least two concrete
20+
consumers or an approved migration plan identifying those consumers. The initial
21+
[Foundry module](foundry/README.md) provides shared project access readiness
22+
(`access/`) and typed errors (`ferrors/`) for the Foundry extensions
23+
(`azure.ai.agents`, `azure.ai.toolboxes`, `azure.ai.skills`, and sibling
24+
`azure.ai.*` extensions). Each consumer is migrated in a separate PR after a
25+
shared-module tag is available.

‎cli/shared/foundry/.golangci.yaml‎

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
version: "2"
2+
linters:
3+
disable:
4+
- errcheck
5+
enable:
6+
- errorlint
7+
- forbidigo
8+
- gosec
9+
- lll
10+
settings:
11+
forbidigo:
12+
analyze-types: true
13+
forbid:
14+
- pattern: ^fmt\.Print.*$
15+
msg: >-
16+
Use t.Log/t.Logf in tests instead of fmt.Print* to avoid
17+
corrupting go test -json output.
18+
- pattern: ^os\.Stdout$
19+
msg: >-
20+
Do not reference os.Stdout in tests; use io.Discard or a
21+
bytes.Buffer.
22+
errorlint:
23+
errorf: true
24+
asserts: true
25+
comparison: true
26+
lll:
27+
line-length: 125
28+
tab-width: 4
29+
gosec:
30+
excludes:
31+
- G304
32+
exclusions:
33+
rules:
34+
- path-except: _test\.go$
35+
linters:
36+
- forbidigo
37+
formatters:
38+
enable:
39+
- gofmt

‎cli/shared/foundry/CHANGELOG.md‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Release History
2+
3+
## 0.1.0 (Unreleased)
4+
5+
### Features Added
6+
7+
- Add `access` package for ARM-first Foundry project data-plane access preparation, role equivalence checks, idempotent role assignment, and bounded propagation/sync polling.
8+
- Add `ferrors` package for portable typed errors across Foundry extensions.

‎cli/shared/foundry/README.md‎

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Shared Foundry module
2+
3+
```go
4+
module github.com/azure/azure-dev/cli/shared/foundry
5+
```
6+
7+
This independently versioned Go library is a build-time dependency for Foundry
8+
extensions. It is not an azd extension or gRPC capability and has no registry
9+
entry. Its `go.mod`, implementation, and transitive build graph must not require
10+
or import `github.com/azure/azure-dev/cli/azd` or extension-internal packages.
11+
12+
## Packages
13+
14+
- **`access/`**: ARM-first Foundry project data-plane access preparation, role
15+
equivalence inspection (`Foundry User`, `Cognitive Services User`,
16+
`Foundry Project Manager`, `Foundry Owner`), general ARM role inspection and
17+
idempotent assignment (`HasAnyRoleAssignment`, `AssignRole`), deterministic
18+
UUIDv5 `RoleAssignmentName` generation, 15-second initial settling, bounded
19+
propagation/sync polling (`Ensure[T]`, `PollReadiness`), and sanitized write
20+
error remediation (`WriteError`).
21+
- **`ferrors/`**: Module-owned typed errors (`*ferrors.Error`, `Category`,
22+
`CodeAuthFailed`) that extensions translate into their local `exterrors` or
23+
`azdext.LocalError` / `azdext.ServiceError` representation at the extension
24+
boundary.
25+
26+
## Versioning and release
27+
28+
The API starts at **v0.x**. Record breaking changes explicitly in release notes;
29+
consumers pin exact released versions. Release independently from azd core and
30+
extension binaries using `cli/shared/foundry/v0.x.y` tags. See
31+
[RELEASING.md](RELEASING.md).
32+
33+
## Development
34+
35+
From `cli/shared/foundry`, independent of the core and extension workspaces:
36+
37+
```sh
38+
GOWORK=off go mod download
39+
GOWORK=off go build ./...
40+
GOWORK=off go test ./... -count=1
41+
GOWORK=off go test -race ./... -count=1 # requires a supported CGO toolchain
42+
GOWORK=off go vet ./...
43+
python eng/check-boundaries.py
44+
```

‎cli/shared/foundry/RELEASING.md‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Releasing the Foundry shared module
2+
3+
This module starts at v0.x and is released independently of azd core and extension
4+
binary artifacts. Publishing a Go module requires a repository tag, not an
5+
`extension.yaml`, extension bundle, or registry update.
6+
7+
Before a release:
8+
9+
1. Merge the reviewed shared-module change and confirm the independent CI passed.
10+
2. Review public API compatibility and update `CHANGELOG.md`. For v0 releases,
11+
explicitly record any breaking changes.
12+
3. Verify `GOWORK=off` build/tests, race tests on a supported platform, and
13+
`python eng/check-boundaries.py` from the module directory.
14+
4. Review dependency updates and compatibility with the proving consumers.
15+
5. An authorized maintainer creates and pushes an annotated tag on the reviewed
16+
commit: `cli/shared/foundry/v0.1.0` for the first release. Do not use the core
17+
`cli/azd/v*` tags or binary `azd-ext-*` tags. Do not create a tag for an
18+
unmerged draft or move a published tag.
19+
6. Verify `GOWORK=off go mod download -json github.com/azure/azure-dev/cli/shared/foundry@v0.1.0`
20+
succeeds through the normal Go module infrastructure.
21+
7. Update each consuming extension's direct dependency to that tag; remove any
22+
draft workspace/replace directives and build/test the extension as its own
23+
module.
24+
25+
For v2 or later, follow Go semantic import versioning, including the `/v2`
26+
module/import suffix.

0 commit comments

Comments
 (0)