Skip to content

Commit 87a8809

Browse files
committed
Add metadata pattern and tag-based filtering to Atmos Profiles PRD
This updates the PRD to use the existing metadata: pattern (consistent with vendoring and stack config) and adds comprehensive tag-based resource filtering capabilities. **Metadata Pattern (Following Existing Atmos Conventions):** Schema Addition: - metadata.name (string) - Profile/config name (auto-populated) - metadata.description (string) - Human-readable description - metadata.version (string) - Semantic version (optional) - metadata.tags ([]string) - Tags for filtering (optional) - metadata.deprecated (bool) - Deprecation marker (optional) Follows pattern from: - Vendoring: metadata.name, metadata.description - Stack config: metadata.name, metadata.description Auto-Population Rules: - Base config (atmos.yaml): metadata.name = "default" if not set - Profile configs: metadata.name = directory basename if not set - Example: profiles/ci/ → metadata.name = "ci" Metadata Merge Behavior (TR2.8): - First non-empty wins: name, description, version, deprecated - Union (append + deduplicate): tags - Best practice: Define in _metadata.yaml or first alphabetical file **Tag-Based Resource Filtering (TR2a):** Use Case: When profile is active, automatically filter resources by matching tags to show only relevant items. Implementation: - Profile tags: metadata.tags: ["developer", "local"] - Resource tags: identity.tags, component.tags, stack.tags - Matching: OR logic (show if ANY tag matches) - Opt-in: --filter-by-profile-tags flag or profiles.filter_by_tags config Commands with Tag Filtering: - atmos auth list identities --filter-by-profile-tags - atmos list components --filter-by-profile-tags - atmos describe stacks --filter-by-profile-tags Example: ```yaml # profiles/developer/_metadata.yaml metadata: tags: ["developer", "local"] # auth identities with tags developer-sandbox: tags: ["developer"] # Shown platform-admin: tags: ["admin"] # Hidden ``` Multiple Profiles: - --profile developer,ci - Tags unioned: ["developer", "local", "ci", "github-actions"] - Resources matching ANY tag shown **Examples Updated:** All profile examples now include metadata: - CI Profile: name, description, version, tags (ci, github-actions) - Developer Profile: name, description, version, tags (development, local) - Debug Profile: name, description, tags (debug, troubleshooting) - Platform Admin: name, description, tags (admin, production) New Section: Tag-Based Resource Filtering - Complete example with 4 identities - Filtered vs unfiltered output comparison - Benefits: Reduces noise, improves UX, clear intent - Multiple profile tag combination example **Schema Updates:** profiles: base_path: "./profiles" metadata: name: default description: "Base Atmos configuration" version: "1.0.0" tags: [] **Benefits:** - Consistent with existing Atmos patterns (metadata:) - No confusion with profiles: vs profile: (single key) - Tag filtering enables context-aware resource discovery - Improves developer UX (only see relevant identities) - Opt-in (backward compatible - disabled by default) - Extensible (works with any resource with tags field)
1 parent 2092001 commit 87a8809

File tree

1 file changed

+255
-2
lines changed

1 file changed

+255
-2
lines changed

docs/prd/atmos-profiles.md

Lines changed: 255 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -390,16 +390,25 @@ active_profiles:
390390

391391
**TR2.2**: Profile configurations MUST be validated using existing Atmos configuration schema
392392

393-
**TR2.3**: New top-level `Profiles` configuration MUST be added to `AtmosConfiguration` in `pkg/schema/schema.go`:
393+
**TR2.3**: New top-level `Profiles` and `Metadata` configuration MUST be added to `AtmosConfiguration` in `pkg/schema/schema.go`:
394394
```go
395395
type AtmosConfiguration struct {
396396
// ... existing fields ...
397397
Profiles ProfilesConfig `yaml:"profiles,omitempty" json:"profiles,omitempty" mapstructure:"profiles"`
398+
Metadata ConfigMetadata `yaml:"metadata,omitempty" json:"metadata,omitempty" mapstructure:"metadata"`
398399
}
399400

400401
type ProfilesConfig struct {
401402
BasePath string `yaml:"base_path,omitempty" json:"base_path,omitempty" mapstructure:"base_path"`
402403
}
404+
405+
type ConfigMetadata struct {
406+
Name string `yaml:"name,omitempty" json:"name,omitempty" mapstructure:"name"`
407+
Description string `yaml:"description,omitempty" json:"description,omitempty" mapstructure:"description"`
408+
Version string `yaml:"version,omitempty" json:"version,omitempty" mapstructure:"version"`
409+
Tags []string `yaml:"tags,omitempty" json:"tags,omitempty" mapstructure:"tags"`
410+
Deprecated bool `yaml:"deprecated,omitempty" json:"deprecated,omitempty" mapstructure:"deprecated"`
411+
}
403412
```
404413

405414
**TR2.4**: JSON Schema definitions in `pkg/datafetcher/schema/` MUST include top-level `profiles` configuration
@@ -408,6 +417,90 @@ type ProfilesConfig struct {
408417

409418
**TR2.6**: Profile imports MUST use the same validation and cycle detection as stack imports
410419

420+
**TR2.7**: Metadata auto-population MUST occur after configuration loading:
421+
- Base config (`atmos.yaml`): Auto-populate `metadata.name` to `"default"` if not set
422+
- Profile configs: Auto-populate `metadata.name` to directory basename if not set
423+
- Example: `profiles/ci/``metadata.name = "ci"`
424+
425+
**TR2.8**: Metadata merge behavior when profile has multiple files:
426+
- **First non-empty wins** for singular fields (`name`, `description`, `version`, `deprecated`)
427+
- **Union (append + deduplicate)** for array fields (`tags`)
428+
- Best practice: Define metadata in `_metadata.yaml` or first alphabetical file
429+
430+
```go
431+
// Metadata merge logic
432+
func mergeConfigMetadata(existing *ConfigMetadata, incoming *ConfigMetadata) {
433+
// First non-empty wins
434+
if existing.Name == "" && incoming.Name != "" {
435+
existing.Name = incoming.Name
436+
}
437+
if existing.Description == "" && incoming.Description != "" {
438+
existing.Description = incoming.Description
439+
}
440+
if existing.Version == "" && incoming.Version != "" {
441+
existing.Version = incoming.Version
442+
}
443+
if !existing.Deprecated && incoming.Deprecated {
444+
existing.Deprecated = incoming.Deprecated
445+
}
446+
447+
// Tags: Union (append and deduplicate)
448+
if len(incoming.Tags) > 0 {
449+
existing.Tags = appendUnique(existing.Tags, incoming.Tags)
450+
}
451+
}
452+
```
453+
454+
#### TR2a: Tag-Based Filtering
455+
456+
**TR2a.1**: Profile tags MUST enable automatic filtering of resources when active
457+
458+
**TR2a.2**: When profile with tags is active, commands MUST filter resources by matching tags:
459+
- `atmos describe stacks` - Show only stacks with matching tags
460+
- `atmos list components` - Show only components with matching tags
461+
- `atmos auth list identities` - Show only identities with matching tags
462+
463+
**TR2a.3**: Tag matching logic:
464+
- If profile has tags `["developer", "local"]`
465+
- Filter matches resources with **any** of those tags (OR logic)
466+
- Example: Identity with `tags: ["developer"]` → Shown
467+
- Example: Identity with `tags: ["production"]` → Hidden
468+
469+
**TR2a.4**: Tag filtering MUST be opt-in via flag or configuration:
470+
- Flag: `--filter-by-profile-tags` (enables automatic filtering)
471+
- Config: `profiles.filter_by_tags: true` (enables by default)
472+
- Default: Disabled (backward compatible - show all resources)
473+
474+
**TR2a.5**: Tag filtering examples:
475+
476+
```yaml
477+
# profiles/developer/_metadata.yaml
478+
metadata:
479+
name: developer
480+
tags: ["developer", "local"]
481+
482+
# When --profile developer --filter-by-profile-tags active:
483+
# Only shows identities/stacks/components with tags: ["developer"] or ["local"]
484+
```
485+
486+
```bash
487+
# List only developer identities when developer profile active
488+
atmos auth list identities --profile developer --filter-by-profile-tags
489+
490+
# Output: Only shows identities tagged with "developer" or "local"
491+
```
492+
493+
**TR2a.6**: Multiple profiles with tag filtering:
494+
- When multiple profiles active: `--profile developer,ci`
495+
- Tags are **unioned**: `["developer", "local", "ci", "github-actions"]`
496+
- Resources matching **any** tag are shown
497+
498+
**TR2a.7**: Tag filtering MUST work with:
499+
- Identity listing: `atmos auth list identities`
500+
- Component listing: `atmos list components`
501+
- Stack listing: `atmos describe stacks`
502+
- Future: Any resource with `tags` field
503+
411504
#### TR3: Performance
412505

413506
**TR3.1**: Profile loading MUST complete within 100ms for typical profiles (<10 files)
@@ -757,6 +850,17 @@ Note: Provenance annotations show the source file and line number where each val
757850
**Note:** This example uses `auth.defaults.identity` from the [Auth Default Settings PRD](./auth-default-settings.md) to provide deterministic identity selection in non-interactive (CI) environments.
758851

759852
```yaml
853+
# profiles/ci/_metadata.yaml (or in auth.yaml as first file)
854+
metadata:
855+
name: ci
856+
description: "GitHub Actions CI/CD environment for production deployments"
857+
version: "2.1.0"
858+
tags:
859+
- ci
860+
- github-actions
861+
- production
862+
- non-interactive
863+
760864
# profiles/ci/auth.yaml
761865
auth:
762866
# Use auth.defaults.identity for deterministic selection in CI (no TTY needed)
@@ -831,6 +935,17 @@ ATMOS_PROFILE=ci ATMOS_IDENTITY=different-identity atmos terraform apply compone
831935
**Note:** This example shows how profiles can use `auth.defaults.identity` to set a sensible default while still allowing multiple identities for quick switching.
832936

833937
```yaml
938+
# profiles/developer/_metadata.yaml
939+
metadata:
940+
name: developer
941+
description: "Developer workstation configuration with AWS SSO"
942+
version: "1.5.0"
943+
tags:
944+
- development
945+
- local
946+
- interactive
947+
- aws-sso
948+
834949
# profiles/developer/auth.yaml
835950
auth:
836951
# Selected default for developer profile
@@ -903,6 +1018,15 @@ atmos terraform plan vpc -s dev --profile developer --identity developer-prod
9031018
#### Debug Profile Example
9041019

9051020
```yaml
1021+
# profiles/debug/_metadata.yaml
1022+
metadata:
1023+
name: debug
1024+
description: "Debug logging and CPU profiling for troubleshooting"
1025+
tags:
1026+
- debug
1027+
- troubleshooting
1028+
- verbose
1029+
9061030
# profiles/debug/logging.yaml
9071031
logs:
9081032
level: Trace
@@ -1007,15 +1131,141 @@ settings:
10071131
3. Later profiles override earlier ones for conflicting settings
10081132
4. In this example: `debug/logging.yaml` overrides `developer/logging.yaml` for `logs.level`
10091133

1134+
#### Tag-Based Resource Filtering
1135+
1136+
**Use Case:** Automatically show only relevant resources when a profile is active.
1137+
1138+
**Configuration:**
1139+
1140+
```yaml
1141+
# profiles/developer/_metadata.yaml
1142+
metadata:
1143+
name: developer
1144+
tags:
1145+
- developer
1146+
- local
1147+
- development
1148+
1149+
# atmos.yaml - Identity configuration with tags
1150+
auth:
1151+
identities:
1152+
developer-sandbox:
1153+
kind: aws/permission-set
1154+
tags: ["developer", "sandbox"] # Matches "developer" tag from profile
1155+
via:
1156+
provider: aws-sso-dev
1157+
principal:
1158+
account_id: "999888777666"
1159+
permission_set: DeveloperAccess
1160+
1161+
developer-prod:
1162+
kind: aws/permission-set
1163+
tags: ["developer", "production"] # Matches "developer" tag from profile
1164+
via:
1165+
provider: aws-sso-prod
1166+
principal:
1167+
account_id: "123456789012"
1168+
permission_set: ReadOnlyAccess
1169+
1170+
platform-admin:
1171+
kind: aws/permission-set
1172+
tags: ["admin", "production"] # Does NOT match profile tags
1173+
via:
1174+
provider: aws-sso-prod
1175+
principal:
1176+
account_id: "123456789012"
1177+
permission_set: AdministratorAccess
1178+
1179+
ci-github-oidc:
1180+
kind: aws/assume-role
1181+
tags: ["ci", "github-actions"] # Does NOT match profile tags
1182+
via:
1183+
provider: github-oidc-provider
1184+
```
1185+
1186+
**Usage with Tag Filtering:**
1187+
1188+
```bash
1189+
# List identities with tag filtering enabled
1190+
atmos auth list identities --profile developer --filter-by-profile-tags
1191+
```
1192+
1193+
**Output (filtered):**
1194+
```
1195+
Available Identities (filtered by profile tags: developer, local, development)
1196+
1197+
┏━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓
1198+
┃ Identity ┃ Kind ┃ Tags ┃
1199+
┡━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━┩
1200+
│ developer-sandbox │ aws/permission-set │ developer, sandbox │
1201+
│ developer-prod │ aws/permission-set │ developer, production │
1202+
└───────────────────┴────────────────────┴────────────────────────┘
1203+
1204+
Showing 2 of 4 total identities (filtered by tags)
1205+
```
1206+
1207+
**Without tag filtering:**
1208+
1209+
```bash
1210+
# Show all identities regardless of tags
1211+
atmos auth list identities --profile developer
1212+
```
1213+
1214+
**Output (unfiltered):**
1215+
```
1216+
Available Identities
1217+
1218+
┏━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓
1219+
┃ Identity ┃ Kind ┃ Tags ┃
1220+
┡━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━┩
1221+
│ developer-sandbox │ aws/permission-set │ developer, sandbox │
1222+
│ developer-prod │ aws/permission-set │ developer, production │
1223+
│ platform-admin │ aws/permission-set │ admin, production │
1224+
│ ci-github-oidc │ aws/assume-role │ ci, github-actions │
1225+
└───────────────────┴────────────────────┴────────────────────────┘
1226+
1227+
Showing 4 identities
1228+
```
1229+
1230+
**Benefits:**
1231+
- **Reduces noise** - Only see relevant resources for your current context
1232+
- **Improves UX** - Developer doesn't see CI/admin identities
1233+
- **Clear intent** - Tags communicate which resources belong to which profiles
1234+
- **Opt-in** - Tag filtering disabled by default (backward compatible)
1235+
1236+
**Multiple Profiles with Tag Filtering:**
1237+
1238+
```bash
1239+
# Activate both developer and ci profiles
1240+
atmos auth list identities --profile developer,ci --filter-by-profile-tags
1241+
```
1242+
1243+
**Result:**
1244+
- Profile tags combined: `["developer", "local", "development", "ci", "github-actions"]`
1245+
- Shows: `developer-sandbox`, `developer-prod`, `ci-github-oidc`
1246+
- Hides: `platform-admin` (no matching tags)
1247+
10101248
#### Platform Admin Profile Example
10111249

10121250
```yaml
1251+
# profiles/platform-admin/_metadata.yaml
1252+
metadata:
1253+
name: platform-admin
1254+
description: "Production platform administrator access"
1255+
tags:
1256+
- admin
1257+
- production
1258+
- privileged
1259+
10131260
# profiles/platform-admin/auth.yaml
10141261
auth:
1262+
defaults:
1263+
identity: platform-admin # Selected default for this profile
1264+
10151265
identities:
10161266
platform-admin:
10171267
kind: aws/permission-set
1018-
default: true # This becomes default when platform-admin profile is active
1268+
tags: ["admin", "production"] # Matches profile tags
10191269
via:
10201270
provider: aws-sso-prod
10211271
principal:
@@ -1032,6 +1282,9 @@ auth:
10321282
Usage:
10331283
```bash
10341284
atmos terraform apply vpc -s prod --profile platform-admin
1285+
1286+
# With tag filtering: Only shows admin-tagged identities
1287+
atmos auth list identities --profile platform-admin --filter-by-profile-tags
10351288
```
10361289

10371290
### Implementation Plan

0 commit comments

Comments
 (0)