aac-cli 0.2.9__tar.gz → 0.2.11__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {aac_cli-0.2.9/aac_cli.egg-info → aac_cli-0.2.11}/PKG-INFO +130 -15
- {aac_cli-0.2.9 → aac_cli-0.2.11}/README.md +129 -14
- {aac_cli-0.2.9 → aac_cli-0.2.11}/aac_cli/__init__.py +1 -1
- aac_cli-0.2.11/aac_cli/__main__.py +13 -0
- {aac_cli-0.2.9 → aac_cli-0.2.11}/aac_cli/admin_key_pem.py +3 -0
- {aac_cli-0.2.9 → aac_cli-0.2.11}/aac_cli/aeg_cli.py +5 -0
- {aac_cli-0.2.9 → aac_cli-0.2.11}/aac_cli/agent_cli.py +15 -2
- {aac_cli-0.2.9 → aac_cli-0.2.11}/aac_cli/agent_health.py +21 -4
- {aac_cli-0.2.9 → aac_cli-0.2.11}/aac_cli/api_key_rotation_state.py +4 -1
- {aac_cli-0.2.9 → aac_cli-0.2.11}/aac_cli/cli.py +549 -293
- {aac_cli-0.2.9 → aac_cli-0.2.11}/aac_cli/config.py +189 -49
- {aac_cli-0.2.9 → aac_cli-0.2.11}/aac_cli/idp_recovery.py +6 -3
- {aac_cli-0.2.9 → aac_cli-0.2.11}/aac_cli/init_cli.py +3 -3
- aac_cli-0.2.11/aac_cli/interrupts.py +48 -0
- {aac_cli-0.2.9 → aac_cli-0.2.11}/aac_cli/profiles.py +114 -59
- {aac_cli-0.2.9 → aac_cli-0.2.11}/aac_cli/reference.py +13 -4
- {aac_cli-0.2.9 → aac_cli-0.2.11}/aac_cli/registration_state.py +30 -18
- aac_cli-0.2.11/aac_cli/safe_output.py +311 -0
- {aac_cli-0.2.9 → aac_cli-0.2.11}/aac_cli/sso_login.py +363 -58
- {aac_cli-0.2.9 → aac_cli-0.2.11/aac_cli.egg-info}/PKG-INFO +130 -15
- {aac_cli-0.2.9 → aac_cli-0.2.11}/aac_cli.egg-info/SOURCES.txt +2 -0
- aac_cli-0.2.11/launchers/aac +36 -0
- aac_cli-0.2.11/launchers/aeg +33 -0
- {aac_cli-0.2.9 → aac_cli-0.2.11}/pyproject.toml +2 -2
- aac_cli-0.2.9/aac_cli/__main__.py +0 -6
- aac_cli-0.2.9/launchers/aac +0 -32
- aac_cli-0.2.9/launchers/aeg +0 -29
- {aac_cli-0.2.9 → aac_cli-0.2.11}/LICENSE +0 -0
- {aac_cli-0.2.9 → aac_cli-0.2.11}/MANIFEST.in +0 -0
- {aac_cli-0.2.9 → aac_cli-0.2.11}/NOTICE +0 -0
- {aac_cli-0.2.9 → aac_cli-0.2.11}/THIRD_PARTY_NOTICES.md +0 -0
- {aac_cli-0.2.9 → aac_cli-0.2.11}/aac_cli/_aeg/__init__.py +0 -0
- {aac_cli-0.2.9 → aac_cli-0.2.11}/aac_cli/_aeg/cli.py +0 -0
- {aac_cli-0.2.9 → aac_cli-0.2.11}/aac_cli/_aeg/data/action-taken-v1.json +0 -0
- {aac_cli-0.2.9 → aac_cli-0.2.11}/aac_cli/_aeg/data/predicates-v1.json +0 -0
- {aac_cli-0.2.9 → aac_cli-0.2.11}/aac_cli/_aeg/data/renderer-source.json +0 -0
- {aac_cli-0.2.9 → aac_cli-0.2.11}/aac_cli/_aeg/from_sidecar.py +0 -0
- {aac_cli-0.2.9 → aac_cli-0.2.11}/aac_cli/_aeg/inputs.py +0 -0
- {aac_cli-0.2.9 → aac_cli-0.2.11}/aac_cli/_aeg/model.py +0 -0
- {aac_cli-0.2.9 → aac_cli-0.2.11}/aac_cli/_aeg/narrative.py +0 -0
- {aac_cli-0.2.9 → aac_cli-0.2.11}/aac_cli/_aeg/provenance.py +0 -0
- {aac_cli-0.2.9 → aac_cli-0.2.11}/aac_cli/_aeg/schemas.py +0 -0
- {aac_cli-0.2.9 → aac_cli-0.2.11}/aac_cli/_aeg/temporal.py +0 -0
- {aac_cli-0.2.9 → aac_cli-0.2.11}/aac_cli/_aeg/theme.py +0 -0
- {aac_cli-0.2.9 → aac_cli-0.2.11}/aac_cli/_aeg/timeline_source.py +0 -0
- {aac_cli-0.2.9 → aac_cli-0.2.11}/aac_cli/_aeg/visualizer.py +0 -0
- {aac_cli-0.2.9 → aac_cli-0.2.11}/aac_cli/aeg_list.py +0 -0
- {aac_cli-0.2.9 → aac_cli-0.2.11}/aac_cli/agent_config.py +0 -0
- {aac_cli-0.2.9 → aac_cli-0.2.11}/aac_cli/agent_layout.py +0 -0
- {aac_cli-0.2.9 → aac_cli-0.2.11}/aac_cli/agent_record.py +0 -0
- {aac_cli-0.2.9 → aac_cli-0.2.11}/aac_cli/chain_list.py +0 -0
- {aac_cli-0.2.9 → aac_cli-0.2.11}/aac_cli/config_render.py +0 -0
- {aac_cli-0.2.9 → aac_cli-0.2.11}/aac_cli/dev_material.py +0 -0
- {aac_cli-0.2.9 → aac_cli-0.2.11}/aac_cli/material_cases.py +0 -0
- {aac_cli-0.2.9 → aac_cli-0.2.11}/aac_cli/secure_files.py +0 -0
- {aac_cli-0.2.9 → aac_cli-0.2.11}/aac_cli/supplied_material.py +0 -0
- {aac_cli-0.2.9 → aac_cli-0.2.11}/aac_cli/trace_query.py +0 -0
- {aac_cli-0.2.9 → aac_cli-0.2.11}/aac_cli.egg-info/dependency_links.txt +0 -0
- {aac_cli-0.2.9 → aac_cli-0.2.11}/aac_cli.egg-info/requires.txt +0 -0
- {aac_cli-0.2.9 → aac_cli-0.2.11}/aac_cli.egg-info/top_level.txt +0 -0
- {aac_cli-0.2.9 → aac_cli-0.2.11}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: aac-cli
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.11
|
|
4
4
|
Summary: The aac platform CLI — headless operator interface to the AAC control plane (tenant registration, chain audit).
|
|
5
5
|
Author: Agent Authority Cloud Project
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -46,8 +46,8 @@ The `aac` command is how a tenant's operator does everything that is not
|
|
|
46
46
|
done by the sidecar itself: register the tenant, sign in, manage keys,
|
|
47
47
|
workloads and domains, and prepare a runnable local workload. Everything
|
|
48
48
|
works from a terminal or a script; there is no web console to click
|
|
49
|
-
through. Output is JSON by default
|
|
50
|
-
|
|
49
|
+
through. Output is JSON by default. Commands that support table output offer
|
|
50
|
+
`--output table`; `aac sso describe` returns JSON only.
|
|
51
51
|
|
|
52
52
|
Two kinds of tenant use the same tool:
|
|
53
53
|
|
|
@@ -741,6 +741,7 @@ aac profile show stage --output table # stored and effective values,
|
|
|
741
741
|
aac profile create prod --admin-url https://aac-admin.example.com \
|
|
742
742
|
--data-plane-url https://aac-data.example.com
|
|
743
743
|
aac profile update main # edit the built-in baseline
|
|
744
|
+
aac profile update stage --unbind # clear the local tenant association
|
|
744
745
|
aac profile delete prod # local only; never touches the server
|
|
745
746
|
```
|
|
746
747
|
|
|
@@ -757,6 +758,41 @@ stored value.
|
|
|
757
758
|
for it; only `aac tenant register`, `aac init` and `aac sso login` write it.
|
|
758
759
|
It is your organisation's identifier in the federation, allocated by AAC at
|
|
759
760
|
registration in the form `tnt-<uuid>`, and it never changes.
|
|
761
|
+
A binding makes that tenant the profile's stored default; it does not grant
|
|
762
|
+
membership or configure an identity provider. Successful sign-in to an existing
|
|
763
|
+
tenant binds the profile; registration binds a newly created tenant.
|
|
764
|
+
|
|
765
|
+
A stale tenant binding affects only that profile. `aac profile list` and
|
|
766
|
+
`aac profile show` mark invalid bindings without printing the invalid values;
|
|
767
|
+
other profiles remain usable. Operational commands reject a selected invalid
|
|
768
|
+
profile with exit 3, even if a tenant flag or environment override is supplied.
|
|
769
|
+
File syntax, profile-name and size limits still apply to the entire file.
|
|
770
|
+
|
|
771
|
+
Use `aac profile update NAME --unbind` to remove the local `tenant_id` and its
|
|
772
|
+
saved hosted-domain metadata. Endpoints, other settings, credentials and the
|
|
773
|
+
server-side tenant are preserved. The flag works without prompts, may accompany
|
|
774
|
+
endpoint flags, and also works on `main` or an already-unbound profile. It
|
|
775
|
+
refuses profiles with unresolved registration or API-key rotation state;
|
|
776
|
+
finish that recovery first. Then bind the profile through registration or
|
|
777
|
+
successful sign-in. Endpoint-only updates and confirmed profile deletion also
|
|
778
|
+
work on stale profiles; reads never rewrite the config file.
|
|
779
|
+
|
|
780
|
+
For an existing tenant, the repair sequence is:
|
|
781
|
+
|
|
782
|
+
```bash
|
|
783
|
+
aac profile update stage --unbind
|
|
784
|
+
# Bind profile stage to the correct existing tenant:
|
|
785
|
+
aac sso login --profile stage --tenant-id '<TENANT_ID>'
|
|
786
|
+
```
|
|
787
|
+
|
|
788
|
+
**`aac sso login --profile stage --tenant-id '<TENANT_ID>'` binds profile
|
|
789
|
+
`stage` to that tenant.** Although the verb is `login`, successful authentication
|
|
790
|
+
also saves the tenant association; there is no separate `--bind` flag. Replace
|
|
791
|
+
`<TENANT_ID>` with the intended tenant's canonical ID. An endpoint correction
|
|
792
|
+
or expired session normally does not need
|
|
793
|
+
unbinding. Unbinding is local and does not log out, revoke access, or change
|
|
794
|
+
existing agent records. See the [profile repair guide](https://docs.cascadeauth.com/cli/guide/#repair-a-stale-profile-binding)
|
|
795
|
+
for the exact config fields removed and recovery constraints.
|
|
760
796
|
|
|
761
797
|
`AAC_CLI_HOME` relocates the whole `~/.aac` tree. Use it for a throwaway
|
|
762
798
|
test home, or to keep separate accounts hard-walled from each other:
|
|
@@ -774,13 +810,39 @@ Two credential files can coexist under `~/.aac/credentials/`:
|
|
|
774
810
|
(`aac chain`, `aac trust-anchor`) present it. Only a hash of it exists
|
|
775
811
|
on the server, so a lost key is replaced, never recovered.
|
|
776
812
|
* `<tenant-id>.session` holds the short-lived session that `aac sso login`
|
|
777
|
-
creates.
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
813
|
+
creates. Authenticated administration commands use it automatically;
|
|
814
|
+
public reads such as `aac sso describe` do not use credentials.
|
|
815
|
+
Sessions have no refresh token. You can sign in again before expiry to
|
|
816
|
+
replace the cached session; after expiry, commands that need it ask you
|
|
817
|
+
to sign in again.
|
|
781
818
|
|
|
782
819
|
## Signing in
|
|
783
820
|
|
|
821
|
+
Inspect the available sign-in connections before starting a login:
|
|
822
|
+
|
|
823
|
+
```bash
|
|
824
|
+
aac sso describe --profile stage # shared/platform candidates
|
|
825
|
+
aac sso describe --profile stage --tenant-id '<TENANT_ID>' # tenant plus shared candidates
|
|
826
|
+
```
|
|
827
|
+
|
|
828
|
+
`sso describe` reads public metadata from the profile's admin endpoint and
|
|
829
|
+
prints the complete descriptor as JSON on stdout. No credentials or prior
|
|
830
|
+
sign-in are required, and it does not bind a profile or change cached credentials.
|
|
831
|
+
The output includes `connections`, `count`, and, for the tenant route,
|
|
832
|
+
`tenant_id`; connection fields describe issuers, client IDs and available flow
|
|
833
|
+
endpoints. An empty connection list is a successful read.
|
|
834
|
+
|
|
835
|
+
Only an explicit `--tenant-id` selects the tenant descriptor. Omitting it
|
|
836
|
+
always reads shared/platform candidates, even when the profile or the
|
|
837
|
+
`AAC_TENANT_ID` environment variable supplies a tenant. Replace `<TENANT_ID>`
|
|
838
|
+
with the intended tenant's canonical ID. The CLI still checks your local
|
|
839
|
+
configuration and selected profile. If it reports an invalid stored tenant
|
|
840
|
+
binding, clear it with `aac profile update stage --unbind`, then retry.
|
|
841
|
+
Output is JSON only (`--output json` is optional); errors go to stderr.
|
|
842
|
+
See the [command reference](https://docs.cascadeauth.com/cli/reference/aac-sso-describe/).
|
|
843
|
+
|
|
844
|
+
Then sign in using the connection you need:
|
|
845
|
+
|
|
784
846
|
```bash
|
|
785
847
|
aac sso login --profile stage --idp github # developer tenant: GitHub or Google
|
|
786
848
|
aac sso login --profile prod \
|
|
@@ -795,14 +857,39 @@ aac sso logout --profile stage
|
|
|
795
857
|
A developer tenant signs in with `--idp github` or `--idp google`; if you
|
|
796
858
|
need another sign-in provider, contact support@cascadeauth.com. An
|
|
797
859
|
enterprise tenant signs in through its Microsoft Entra ID connection, named
|
|
798
|
-
by the connection's exact URL with `--idp-url
|
|
799
|
-
|
|
860
|
+
by the connection's exact URL with `--idp-url`. With neither flag, the
|
|
861
|
+
tenant's own connections take precedence over the shared developer sign-ins;
|
|
862
|
+
when several remain, a terminal shows a numbered list to choose from and then
|
|
863
|
+
prints the flag that skips the prompt next time, while a script (no terminal)
|
|
864
|
+
gets exit 3 and one copy-ready command per connection. The list marks which
|
|
865
|
+
connection the cached session was last obtained through; it never shows
|
|
866
|
+
which connections have members. A developer tenant admits only the provider
|
|
867
|
+
and account it was registered with: when the AAC STS does not accept a shared
|
|
868
|
+
sign-in, the CLI reminds you of that rule and lists any other shared sign-ins. GitHub connections accept the device flow
|
|
869
|
+
only: `--flow pkce` with a GitHub connection stops locally with exit 3.
|
|
870
|
+
|
|
871
|
+
Sessions last **4 hours by default**. Your administrator may configure a
|
|
872
|
+
different lifetime for the deployment or connection. You can run
|
|
873
|
+
`aac sso login` again before expiry: successful authentication replaces the
|
|
874
|
+
cached session with a new one whose lifetime starts at that login. For example,
|
|
875
|
+
with the four-hour default, signing in at 09:00 gives an expiry of 13:00;
|
|
876
|
+
signing in successfully again at 12:00 gives the new session an expiry of 16:00.
|
|
877
|
+
Use `aac sso whoami --profile NAME --output table` to check the current
|
|
878
|
+
expiration. If the session expires, sign in again; no refresh token is issued.
|
|
879
|
+
A command that needs a session stops locally with exit 3 when none is cached,
|
|
880
|
+
before anything is sent, and prints the `aac sso login` command for the same
|
|
881
|
+
profile and endpoints; commands that also accept a bootstrap token name that
|
|
882
|
+
alternative.
|
|
800
883
|
|
|
801
884
|
Sign-in uses the device flow by default, so the browser can be on another
|
|
802
|
-
machine and headless hosts work.
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
885
|
+
machine and headless hosts work. On a terminal with a browser at hand
|
|
886
|
+
(macOS, a desktop session, or `BROWSER` set), the device flow also offers to
|
|
887
|
+
open the sign-in page for you: press Enter to open it in your browser, or copy
|
|
888
|
+
the printed link and code into a browser yourself; `--no-browser` turns the
|
|
889
|
+
offer off, and a script (no terminal) or a headless host never sees it. Google
|
|
890
|
+
connections use a loopback flow instead, because Google's device flow is
|
|
891
|
+
scope-restricted; `--flow` overrides the choice. `whoami` and `logout` work
|
|
892
|
+
offline and never contact AAC.
|
|
806
893
|
|
|
807
894
|
## Output and exit codes
|
|
808
895
|
|
|
@@ -814,11 +901,16 @@ server-returned domain. Existing agents expose read-only identities through
|
|
|
814
901
|
or `--field workload-spiffe-id`. A successful scalar is one unquoted line;
|
|
815
902
|
an unavailable value or unhealthy agent fails with empty stdout. `--field`
|
|
816
903
|
cannot be combined with explicit `--output`, or with agent `--remote`.
|
|
904
|
+
Scalar profile inspection rejects an invalid stored binding. Structured
|
|
905
|
+
inspection remains available and reports invalid effective IDs as `null` with
|
|
906
|
+
an `error`; invalid list bindings carry `binding_error`, and show bindings carry
|
|
907
|
+
`binding.error`. Their invalid stored tenant IDs are redacted as `null`.
|
|
817
908
|
|
|
818
909
|
Every command that reports a result prints one JSON document to standard
|
|
819
910
|
output by default, with progress notes and diagnostics on standard error,
|
|
820
|
-
so the JSON stays parseable in scripts; `--output table`
|
|
821
|
-
table instead.
|
|
911
|
+
so the JSON stays parseable in scripts; where supported, `--output table`
|
|
912
|
+
prints a readable table instead. `aac sso describe` supports JSON only.
|
|
913
|
+
The three profile writers are the exception: `aac profile
|
|
822
914
|
create`, `update` and `delete` confirm on standard error, leave standard
|
|
823
915
|
output empty and take no `--output`.
|
|
824
916
|
|
|
@@ -829,10 +921,33 @@ output empty and take no `--output`.
|
|
|
829
921
|
| `2` | Usage error: an invalid flag, value or flag combination. |
|
|
830
922
|
| `3` | A local configuration or state problem: profile, credential file, cached session or agent. |
|
|
831
923
|
| `4` | Transport failure: an endpoint could not be reached. |
|
|
924
|
+
| `130` | Interrupted by the operator (Ctrl-C). |
|
|
925
|
+
|
|
926
|
+
Ctrl-C stops `aac` and CLI-owned `aeg` without a traceback, with one concise
|
|
927
|
+
diagnostic on standard error. A remote change may already have committed;
|
|
928
|
+
follow any recovery guidance and retain pending registration or key-operation
|
|
929
|
+
state. The CLI does not roll back or automatically retry a remote change.
|
|
930
|
+
|
|
931
|
+
Walking away from sign-in retains the existing deadlines: device sign-in waits
|
|
932
|
+
for the identity provider's device-code lifetime (300 seconds if absent), then
|
|
933
|
+
exits `1` with instructions to run login again; a PKCE browser sign-in without
|
|
934
|
+
a callback gives up after 300 seconds with exit `3`. HTTP timeouts remain exit
|
|
935
|
+
`4`. These outcomes are distinct from Ctrl-C; there is no shorter patience cap.
|
|
832
936
|
|
|
833
937
|
If AAC asks you to slow down, the command shows the interval to wait. The
|
|
834
938
|
CLI never replays a change on its own; wait and rerun deliberately.
|
|
835
939
|
|
|
940
|
+
The commands that can present a ceremony token (`aac tenant register`,
|
|
941
|
+
`reissue-api-key`, `assign-hosted-domain`, `reactivate-hosted-domain`,
|
|
942
|
+
`bind-trust-domain`, `list-trust-domains`, `revoke-trust-domain`,
|
|
943
|
+
`rotate-admin-key`, `aac sso register-idp`, `enroll-idp-recovery-key` and
|
|
944
|
+
`approve-idp-repair`) and `aac sso login` report a failure by HTTP status and
|
|
945
|
+
AAC error code only, never the server's message or response body, because
|
|
946
|
+
either can echo the credential the request carried; their transport failures
|
|
947
|
+
show the error class and the operating system's reason, not the library's
|
|
948
|
+
text. Other commands still print the server's message with the status and
|
|
949
|
+
code.
|
|
950
|
+
|
|
836
951
|
## Enterprise tenants
|
|
837
952
|
|
|
838
953
|
Enterprise tenants are registered through an onboarding ceremony: AAC
|
|
@@ -19,8 +19,8 @@ The `aac` command is how a tenant's operator does everything that is not
|
|
|
19
19
|
done by the sidecar itself: register the tenant, sign in, manage keys,
|
|
20
20
|
workloads and domains, and prepare a runnable local workload. Everything
|
|
21
21
|
works from a terminal or a script; there is no web console to click
|
|
22
|
-
through. Output is JSON by default
|
|
23
|
-
|
|
22
|
+
through. Output is JSON by default. Commands that support table output offer
|
|
23
|
+
`--output table`; `aac sso describe` returns JSON only.
|
|
24
24
|
|
|
25
25
|
Two kinds of tenant use the same tool:
|
|
26
26
|
|
|
@@ -714,6 +714,7 @@ aac profile show stage --output table # stored and effective values,
|
|
|
714
714
|
aac profile create prod --admin-url https://aac-admin.example.com \
|
|
715
715
|
--data-plane-url https://aac-data.example.com
|
|
716
716
|
aac profile update main # edit the built-in baseline
|
|
717
|
+
aac profile update stage --unbind # clear the local tenant association
|
|
717
718
|
aac profile delete prod # local only; never touches the server
|
|
718
719
|
```
|
|
719
720
|
|
|
@@ -730,6 +731,41 @@ stored value.
|
|
|
730
731
|
for it; only `aac tenant register`, `aac init` and `aac sso login` write it.
|
|
731
732
|
It is your organisation's identifier in the federation, allocated by AAC at
|
|
732
733
|
registration in the form `tnt-<uuid>`, and it never changes.
|
|
734
|
+
A binding makes that tenant the profile's stored default; it does not grant
|
|
735
|
+
membership or configure an identity provider. Successful sign-in to an existing
|
|
736
|
+
tenant binds the profile; registration binds a newly created tenant.
|
|
737
|
+
|
|
738
|
+
A stale tenant binding affects only that profile. `aac profile list` and
|
|
739
|
+
`aac profile show` mark invalid bindings without printing the invalid values;
|
|
740
|
+
other profiles remain usable. Operational commands reject a selected invalid
|
|
741
|
+
profile with exit 3, even if a tenant flag or environment override is supplied.
|
|
742
|
+
File syntax, profile-name and size limits still apply to the entire file.
|
|
743
|
+
|
|
744
|
+
Use `aac profile update NAME --unbind` to remove the local `tenant_id` and its
|
|
745
|
+
saved hosted-domain metadata. Endpoints, other settings, credentials and the
|
|
746
|
+
server-side tenant are preserved. The flag works without prompts, may accompany
|
|
747
|
+
endpoint flags, and also works on `main` or an already-unbound profile. It
|
|
748
|
+
refuses profiles with unresolved registration or API-key rotation state;
|
|
749
|
+
finish that recovery first. Then bind the profile through registration or
|
|
750
|
+
successful sign-in. Endpoint-only updates and confirmed profile deletion also
|
|
751
|
+
work on stale profiles; reads never rewrite the config file.
|
|
752
|
+
|
|
753
|
+
For an existing tenant, the repair sequence is:
|
|
754
|
+
|
|
755
|
+
```bash
|
|
756
|
+
aac profile update stage --unbind
|
|
757
|
+
# Bind profile stage to the correct existing tenant:
|
|
758
|
+
aac sso login --profile stage --tenant-id '<TENANT_ID>'
|
|
759
|
+
```
|
|
760
|
+
|
|
761
|
+
**`aac sso login --profile stage --tenant-id '<TENANT_ID>'` binds profile
|
|
762
|
+
`stage` to that tenant.** Although the verb is `login`, successful authentication
|
|
763
|
+
also saves the tenant association; there is no separate `--bind` flag. Replace
|
|
764
|
+
`<TENANT_ID>` with the intended tenant's canonical ID. An endpoint correction
|
|
765
|
+
or expired session normally does not need
|
|
766
|
+
unbinding. Unbinding is local and does not log out, revoke access, or change
|
|
767
|
+
existing agent records. See the [profile repair guide](https://docs.cascadeauth.com/cli/guide/#repair-a-stale-profile-binding)
|
|
768
|
+
for the exact config fields removed and recovery constraints.
|
|
733
769
|
|
|
734
770
|
`AAC_CLI_HOME` relocates the whole `~/.aac` tree. Use it for a throwaway
|
|
735
771
|
test home, or to keep separate accounts hard-walled from each other:
|
|
@@ -747,13 +783,39 @@ Two credential files can coexist under `~/.aac/credentials/`:
|
|
|
747
783
|
(`aac chain`, `aac trust-anchor`) present it. Only a hash of it exists
|
|
748
784
|
on the server, so a lost key is replaced, never recovered.
|
|
749
785
|
* `<tenant-id>.session` holds the short-lived session that `aac sso login`
|
|
750
|
-
creates.
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
786
|
+
creates. Authenticated administration commands use it automatically;
|
|
787
|
+
public reads such as `aac sso describe` do not use credentials.
|
|
788
|
+
Sessions have no refresh token. You can sign in again before expiry to
|
|
789
|
+
replace the cached session; after expiry, commands that need it ask you
|
|
790
|
+
to sign in again.
|
|
754
791
|
|
|
755
792
|
## Signing in
|
|
756
793
|
|
|
794
|
+
Inspect the available sign-in connections before starting a login:
|
|
795
|
+
|
|
796
|
+
```bash
|
|
797
|
+
aac sso describe --profile stage # shared/platform candidates
|
|
798
|
+
aac sso describe --profile stage --tenant-id '<TENANT_ID>' # tenant plus shared candidates
|
|
799
|
+
```
|
|
800
|
+
|
|
801
|
+
`sso describe` reads public metadata from the profile's admin endpoint and
|
|
802
|
+
prints the complete descriptor as JSON on stdout. No credentials or prior
|
|
803
|
+
sign-in are required, and it does not bind a profile or change cached credentials.
|
|
804
|
+
The output includes `connections`, `count`, and, for the tenant route,
|
|
805
|
+
`tenant_id`; connection fields describe issuers, client IDs and available flow
|
|
806
|
+
endpoints. An empty connection list is a successful read.
|
|
807
|
+
|
|
808
|
+
Only an explicit `--tenant-id` selects the tenant descriptor. Omitting it
|
|
809
|
+
always reads shared/platform candidates, even when the profile or the
|
|
810
|
+
`AAC_TENANT_ID` environment variable supplies a tenant. Replace `<TENANT_ID>`
|
|
811
|
+
with the intended tenant's canonical ID. The CLI still checks your local
|
|
812
|
+
configuration and selected profile. If it reports an invalid stored tenant
|
|
813
|
+
binding, clear it with `aac profile update stage --unbind`, then retry.
|
|
814
|
+
Output is JSON only (`--output json` is optional); errors go to stderr.
|
|
815
|
+
See the [command reference](https://docs.cascadeauth.com/cli/reference/aac-sso-describe/).
|
|
816
|
+
|
|
817
|
+
Then sign in using the connection you need:
|
|
818
|
+
|
|
757
819
|
```bash
|
|
758
820
|
aac sso login --profile stage --idp github # developer tenant: GitHub or Google
|
|
759
821
|
aac sso login --profile prod \
|
|
@@ -768,14 +830,39 @@ aac sso logout --profile stage
|
|
|
768
830
|
A developer tenant signs in with `--idp github` or `--idp google`; if you
|
|
769
831
|
need another sign-in provider, contact support@cascadeauth.com. An
|
|
770
832
|
enterprise tenant signs in through its Microsoft Entra ID connection, named
|
|
771
|
-
by the connection's exact URL with `--idp-url
|
|
772
|
-
|
|
833
|
+
by the connection's exact URL with `--idp-url`. With neither flag, the
|
|
834
|
+
tenant's own connections take precedence over the shared developer sign-ins;
|
|
835
|
+
when several remain, a terminal shows a numbered list to choose from and then
|
|
836
|
+
prints the flag that skips the prompt next time, while a script (no terminal)
|
|
837
|
+
gets exit 3 and one copy-ready command per connection. The list marks which
|
|
838
|
+
connection the cached session was last obtained through; it never shows
|
|
839
|
+
which connections have members. A developer tenant admits only the provider
|
|
840
|
+
and account it was registered with: when the AAC STS does not accept a shared
|
|
841
|
+
sign-in, the CLI reminds you of that rule and lists any other shared sign-ins. GitHub connections accept the device flow
|
|
842
|
+
only: `--flow pkce` with a GitHub connection stops locally with exit 3.
|
|
843
|
+
|
|
844
|
+
Sessions last **4 hours by default**. Your administrator may configure a
|
|
845
|
+
different lifetime for the deployment or connection. You can run
|
|
846
|
+
`aac sso login` again before expiry: successful authentication replaces the
|
|
847
|
+
cached session with a new one whose lifetime starts at that login. For example,
|
|
848
|
+
with the four-hour default, signing in at 09:00 gives an expiry of 13:00;
|
|
849
|
+
signing in successfully again at 12:00 gives the new session an expiry of 16:00.
|
|
850
|
+
Use `aac sso whoami --profile NAME --output table` to check the current
|
|
851
|
+
expiration. If the session expires, sign in again; no refresh token is issued.
|
|
852
|
+
A command that needs a session stops locally with exit 3 when none is cached,
|
|
853
|
+
before anything is sent, and prints the `aac sso login` command for the same
|
|
854
|
+
profile and endpoints; commands that also accept a bootstrap token name that
|
|
855
|
+
alternative.
|
|
773
856
|
|
|
774
857
|
Sign-in uses the device flow by default, so the browser can be on another
|
|
775
|
-
machine and headless hosts work.
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
858
|
+
machine and headless hosts work. On a terminal with a browser at hand
|
|
859
|
+
(macOS, a desktop session, or `BROWSER` set), the device flow also offers to
|
|
860
|
+
open the sign-in page for you: press Enter to open it in your browser, or copy
|
|
861
|
+
the printed link and code into a browser yourself; `--no-browser` turns the
|
|
862
|
+
offer off, and a script (no terminal) or a headless host never sees it. Google
|
|
863
|
+
connections use a loopback flow instead, because Google's device flow is
|
|
864
|
+
scope-restricted; `--flow` overrides the choice. `whoami` and `logout` work
|
|
865
|
+
offline and never contact AAC.
|
|
779
866
|
|
|
780
867
|
## Output and exit codes
|
|
781
868
|
|
|
@@ -787,11 +874,16 @@ server-returned domain. Existing agents expose read-only identities through
|
|
|
787
874
|
or `--field workload-spiffe-id`. A successful scalar is one unquoted line;
|
|
788
875
|
an unavailable value or unhealthy agent fails with empty stdout. `--field`
|
|
789
876
|
cannot be combined with explicit `--output`, or with agent `--remote`.
|
|
877
|
+
Scalar profile inspection rejects an invalid stored binding. Structured
|
|
878
|
+
inspection remains available and reports invalid effective IDs as `null` with
|
|
879
|
+
an `error`; invalid list bindings carry `binding_error`, and show bindings carry
|
|
880
|
+
`binding.error`. Their invalid stored tenant IDs are redacted as `null`.
|
|
790
881
|
|
|
791
882
|
Every command that reports a result prints one JSON document to standard
|
|
792
883
|
output by default, with progress notes and diagnostics on standard error,
|
|
793
|
-
so the JSON stays parseable in scripts; `--output table`
|
|
794
|
-
table instead.
|
|
884
|
+
so the JSON stays parseable in scripts; where supported, `--output table`
|
|
885
|
+
prints a readable table instead. `aac sso describe` supports JSON only.
|
|
886
|
+
The three profile writers are the exception: `aac profile
|
|
795
887
|
create`, `update` and `delete` confirm on standard error, leave standard
|
|
796
888
|
output empty and take no `--output`.
|
|
797
889
|
|
|
@@ -802,10 +894,33 @@ output empty and take no `--output`.
|
|
|
802
894
|
| `2` | Usage error: an invalid flag, value or flag combination. |
|
|
803
895
|
| `3` | A local configuration or state problem: profile, credential file, cached session or agent. |
|
|
804
896
|
| `4` | Transport failure: an endpoint could not be reached. |
|
|
897
|
+
| `130` | Interrupted by the operator (Ctrl-C). |
|
|
898
|
+
|
|
899
|
+
Ctrl-C stops `aac` and CLI-owned `aeg` without a traceback, with one concise
|
|
900
|
+
diagnostic on standard error. A remote change may already have committed;
|
|
901
|
+
follow any recovery guidance and retain pending registration or key-operation
|
|
902
|
+
state. The CLI does not roll back or automatically retry a remote change.
|
|
903
|
+
|
|
904
|
+
Walking away from sign-in retains the existing deadlines: device sign-in waits
|
|
905
|
+
for the identity provider's device-code lifetime (300 seconds if absent), then
|
|
906
|
+
exits `1` with instructions to run login again; a PKCE browser sign-in without
|
|
907
|
+
a callback gives up after 300 seconds with exit `3`. HTTP timeouts remain exit
|
|
908
|
+
`4`. These outcomes are distinct from Ctrl-C; there is no shorter patience cap.
|
|
805
909
|
|
|
806
910
|
If AAC asks you to slow down, the command shows the interval to wait. The
|
|
807
911
|
CLI never replays a change on its own; wait and rerun deliberately.
|
|
808
912
|
|
|
913
|
+
The commands that can present a ceremony token (`aac tenant register`,
|
|
914
|
+
`reissue-api-key`, `assign-hosted-domain`, `reactivate-hosted-domain`,
|
|
915
|
+
`bind-trust-domain`, `list-trust-domains`, `revoke-trust-domain`,
|
|
916
|
+
`rotate-admin-key`, `aac sso register-idp`, `enroll-idp-recovery-key` and
|
|
917
|
+
`approve-idp-repair`) and `aac sso login` report a failure by HTTP status and
|
|
918
|
+
AAC error code only, never the server's message or response body, because
|
|
919
|
+
either can echo the credential the request carried; their transport failures
|
|
920
|
+
show the error class and the operating system's reason, not the library's
|
|
921
|
+
text. Other commands still print the server's message with the status and
|
|
922
|
+
code.
|
|
923
|
+
|
|
809
924
|
## Enterprise tenants
|
|
810
925
|
|
|
811
926
|
Enterprise tenants are registered through an onboarding ceremony: AAC
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""`python -m aac_cli` — same entrypoint as the `aac` console script."""
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
try:
|
|
6
|
+
from aac_cli.cli import entrypoint
|
|
7
|
+
|
|
8
|
+
if __name__ == "__main__":
|
|
9
|
+
entrypoint()
|
|
10
|
+
except KeyboardInterrupt:
|
|
11
|
+
# The shared command boundary is not loaded during early imports.
|
|
12
|
+
sys.stderr.write("aac: interrupted\n")
|
|
13
|
+
raise SystemExit(130) from None
|
|
@@ -223,6 +223,9 @@ def require_ed25519_public_key_pem(text: str) -> str:
|
|
|
223
223
|
try:
|
|
224
224
|
der = base64.b64decode(encoded, validate=True)
|
|
225
225
|
except (binascii.Error, ValueError) as exc:
|
|
226
|
+
# The decoder's text names the fault ("Incorrect padding", a bad
|
|
227
|
+
# character's position) and never quotes the data, which is what keeps
|
|
228
|
+
# AdminKeyPemError on the CLI-composed list of the diagnostic contract.
|
|
226
229
|
raise AdminKeyPemError(f"PEM body is not valid base64: {exc}") from exc
|
|
227
230
|
|
|
228
231
|
if len(der) != _ED25519_SPKI_LENGTH or not der.startswith(_ED25519_SPKI_PREFIX):
|
|
@@ -7,6 +7,7 @@ import sys
|
|
|
7
7
|
from importlib.resources import files
|
|
8
8
|
|
|
9
9
|
from . import __version__
|
|
10
|
+
from .interrupts import run_command
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
def version_text() -> str:
|
|
@@ -15,6 +16,10 @@ def version_text() -> str:
|
|
|
15
16
|
|
|
16
17
|
|
|
17
18
|
def main(argv: list[str] | None = None) -> int:
|
|
19
|
+
return run_command(lambda: _main(argv), prog="aeg")
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _main(argv: list[str] | None = None) -> int:
|
|
18
23
|
argv = list(sys.argv[1:] if argv is None else argv)
|
|
19
24
|
if argv == ["--version"]:
|
|
20
25
|
print(version_text())
|
|
@@ -619,13 +619,21 @@ def cmd_agent_list(args: argparse.Namespace) -> int:
|
|
|
619
619
|
row["certificates"] = case_for(record.material_source).name
|
|
620
620
|
tenant = tenant_paths(record.tenant_id) if record.tenant_id else None
|
|
621
621
|
health = assess(agent, tenant, record)
|
|
622
|
+
row["profile_binding_consistent"] = health.profile_binding_consistent
|
|
622
623
|
row["next_command"] = next_step(agent, tenant, record, health)
|
|
623
624
|
rows.append(row)
|
|
624
625
|
if args.output == "table":
|
|
625
626
|
if not rows:
|
|
626
627
|
print(f"no agents under {directory}")
|
|
627
628
|
for row in rows:
|
|
628
|
-
|
|
629
|
+
binding_note = (
|
|
630
|
+
" (profile binding inconsistent)"
|
|
631
|
+
if row.get("profile_binding_consistent") is False
|
|
632
|
+
else ""
|
|
633
|
+
)
|
|
634
|
+
print(
|
|
635
|
+
f"{row['agent']:<16}: {row.get('certificates', row.get('state', '-'))}{binding_note}"
|
|
636
|
+
)
|
|
629
637
|
return 0
|
|
630
638
|
print(json.dumps({"agents": rows}, indent=2))
|
|
631
639
|
return 0
|
|
@@ -708,7 +716,12 @@ def add_agent_parser(nouns: argparse._SubParsersAction) -> None:
|
|
|
708
716
|
listing = verbs.add_parser(
|
|
709
717
|
"list",
|
|
710
718
|
help="List every agent under the CLI home with its tenant, case and state.",
|
|
711
|
-
description=
|
|
719
|
+
description=(
|
|
720
|
+
"List every agent; an unreadable or unsupported record is reported in that "
|
|
721
|
+
"agent's state without hiding the other agents. Invalid profile bindings "
|
|
722
|
+
"are reported per agent: JSON includes profile_binding_consistent and the "
|
|
723
|
+
"repair next_command; table output marks inconsistent bindings."
|
|
724
|
+
),
|
|
712
725
|
)
|
|
713
726
|
listing.add_argument(
|
|
714
727
|
"--output", choices=("json", "table"), default="json", help="Output mode (JSON by default)."
|
|
@@ -22,7 +22,13 @@ from aac_cli.agent_layout import (
|
|
|
22
22
|
material_inventory,
|
|
23
23
|
)
|
|
24
24
|
from aac_cli.agent_record import STEP_MATERIAL, AgentRecord
|
|
25
|
-
from aac_cli.config import
|
|
25
|
+
from aac_cli.config import (
|
|
26
|
+
CliConfigError,
|
|
27
|
+
cli_home,
|
|
28
|
+
credentials_path,
|
|
29
|
+
profile_binding_error,
|
|
30
|
+
read_profile_section,
|
|
31
|
+
)
|
|
26
32
|
from aac_cli.material_cases import MATERIAL_ISSUED_HERE, MATERIAL_SUPPLIED, ca_report_label
|
|
27
33
|
from aac_cli.secure_files import managed_path_problem
|
|
28
34
|
|
|
@@ -40,6 +46,7 @@ class CertificateReport:
|
|
|
40
46
|
class AgentHealth:
|
|
41
47
|
setup_complete: bool
|
|
42
48
|
profile_binding_consistent: bool
|
|
49
|
+
invalid_profile_binding: bool = False
|
|
43
50
|
missing_files: list[str] = field(default_factory=list)
|
|
44
51
|
permission_problems: list[str] = field(default_factory=list)
|
|
45
52
|
certificates: dict[str, CertificateReport] = field(default_factory=dict)
|
|
@@ -74,7 +81,9 @@ class AgentHealth:
|
|
|
74
81
|
reasons: list[str] = []
|
|
75
82
|
if not self.setup_complete:
|
|
76
83
|
reasons.append("setup is incomplete")
|
|
77
|
-
if
|
|
84
|
+
if self.invalid_profile_binding:
|
|
85
|
+
reasons.append("the profile has an invalid stored tenant binding")
|
|
86
|
+
elif not self.profile_binding_consistent:
|
|
78
87
|
reasons.append("the profile is bound to a different tenant than this agent")
|
|
79
88
|
reasons.extend(f"missing: {name}" for name in self.missing_files)
|
|
80
89
|
reasons.extend(self.permission_problems)
|
|
@@ -111,10 +120,16 @@ def _certificate_reports(
|
|
|
111
120
|
|
|
112
121
|
def assess(agent: AgentPaths, tenant: TenantPaths | None, record: AgentRecord) -> AgentHealth:
|
|
113
122
|
"""The offline health assessment both `status` and a completed `init` report."""
|
|
114
|
-
|
|
123
|
+
# Offline inventory diagnoses this agent's profile without allowing one
|
|
124
|
+
# stale association to abort every other agent's inventory. Operational
|
|
125
|
+
# profile resolution stays strict; material paths use the validated record.
|
|
126
|
+
stored = read_profile_section(record.profile, validate_binding=False)
|
|
127
|
+
invalid_binding = profile_binding_error(stored) is not None
|
|
115
128
|
health = AgentHealth(
|
|
116
129
|
setup_complete=record.next_step() is None,
|
|
117
|
-
profile_binding_consistent=
|
|
130
|
+
profile_binding_consistent=not invalid_binding
|
|
131
|
+
and stored.get("tenant_id") == record.tenant_id,
|
|
132
|
+
invalid_profile_binding=invalid_binding,
|
|
118
133
|
)
|
|
119
134
|
if tenant is None:
|
|
120
135
|
return health
|
|
@@ -387,6 +402,8 @@ def next_step(
|
|
|
387
402
|
) -> str | None:
|
|
388
403
|
"""The one next step `status` reports and a refused `init` names; None when there is none."""
|
|
389
404
|
agent_flag = f"--agent {_quote(agent.name)}"
|
|
405
|
+
if health.invalid_profile_binding:
|
|
406
|
+
return f"aac profile update {_quote(record.profile)} --unbind"
|
|
390
407
|
if not health.setup_complete:
|
|
391
408
|
return f"aac init --profile {_quote(record.profile)} {agent_flag}"
|
|
392
409
|
if tenant is not None:
|
|
@@ -16,6 +16,7 @@ from aac_cli.config import (
|
|
|
16
16
|
cli_home,
|
|
17
17
|
credentials_path,
|
|
18
18
|
)
|
|
19
|
+
from aac_cli.safe_output import failure_class
|
|
19
20
|
|
|
20
21
|
__all__ = [
|
|
21
22
|
"ROTATION_STATE_WARNING",
|
|
@@ -97,7 +98,9 @@ def read_rotation_state(profile: str) -> RotationIssueState | None:
|
|
|
97
98
|
except FileNotFoundError:
|
|
98
99
|
return None
|
|
99
100
|
except OSError as exc:
|
|
100
|
-
raise CliConfigError(
|
|
101
|
+
raise CliConfigError(
|
|
102
|
+
f"cannot read API-key rotation state {path}: {failure_class(exc)}"
|
|
103
|
+
) from exc
|
|
101
104
|
if len(raw) > _MAX_STATE_BYTES:
|
|
102
105
|
raise CliConfigError(f"API-key rotation state {path} exceeds {_MAX_STATE_BYTES} bytes")
|
|
103
106
|
try:
|