feat: l for details; details for vaults, scopes and files; getting started; the age of cached lists #17

Merged
keb merged 17 commits from feat/l-for-details into main 2026-10-11 14:24:09 +02:00
2 changed files with 17 additions and 7 deletions
Showing only changes of commit 4b2a6a8ae8 - Show all commits

No files matched your search

+10 -5
View File
@@ -318,18 +318,23 @@ func (p *Provider) Value(ctx context.Context, o provider.Object) (provider.Secre
} }
// deniedChecks are what to check when Databricks refuses: the network, // deniedChecks are what to check when Databricks refuses: the network,
// when the workspace's IP access list refused, else access. // when the workspace's IP access list refused, else access, and for a
func deniedChecks(msg string) []string { // profile signed in through az, which account az is on.
func deniedChecks(pr profile, msg string) []string {
if strings.Contains(msg, "IP ACL") || strings.Contains(msg, "IP access list") { if strings.Contains(msg, "IP ACL") || strings.Contains(msg, "IP access list") {
return []string{ return []string{
"you're on a network the workspace lets in (VPN, office)", "you're on a network the workspace lets in (VPN, office)",
"the workspace's admin has let your network in", "the workspace's admin has let your network in",
} }
} }
return []string{ var checks []string
if pr.authType == "azure-cli" {
checks = append(checks, "az is signed in as the account with access: profile "+pr.name+" uses your az login (az account show)")
}
return append(checks,
"you have access to the workspace", "you have access to the workspace",
"the scope's manager has given you READ on it, or a group you're in", "the scope's manager has given you READ on it, or a group you're in",
} )
} }
var errNoFallback = errors.New("no Key Vault fallback") var errNoFallback = errors.New("no Key Vault fallback")
@@ -369,7 +374,7 @@ func classify(pr profile, err error) error {
var api *apierr.APIError var api *apierr.APIError
if errors.As(err, &api) { if errors.As(err, &api) {
if api.StatusCode == 403 { if api.StatusCode == 403 {
return &provider.Denied{Err: err, Checks: deniedChecks(api.Message)} return &provider.Denied{Err: err, Checks: deniedChecks(pr, api.Message)}
} }
if api.StatusCode != 401 { if api.StatusCode != 401 {
return err return err
@@ -322,10 +322,15 @@ func TestDeniedSaysWhatToCheck(t *testing.T) {
p := newTestProvider(t, workspaceAPI(t, 0), nil) p := newTestProvider(t, workspaceAPI(t, 0), nil)
_, err := p.Objects(context.Background(), provider.Container{Source: provider.Source{ID: "prod"}, Name: "locked"}, provider.TypeSecret) _, err := p.Objects(context.Background(), provider.Container{Source: provider.Source{ID: "prod"}, Name: "locked"}, provider.TypeSecret)
var d *provider.Denied var d *provider.Denied
if !errors.As(err, &d) || !strings.Contains(err.Error(), "READ permission on scope locked\n\nCheck:\n• you have access to the workspace") { // The test profile signs in through az: that's the first check.
if !errors.As(err, &d) || !strings.Contains(err.Error(), "READ permission on scope locked\n\nCheck:\n• az is signed in as the account with access: profile prod uses your az login") ||
!strings.Contains(err.Error(), "\n• you have access to the workspace") {
t.Errorf("err %q", err) t.Errorf("err %q", err)
} }
if got := deniedChecks("Source IP address: 1.2.3.4 is blocked by Databricks IP ACL for workspace: 1"); !strings.Contains(got[0], "network") { if got := deniedChecks(profile{authType: "pat"}, "denied"); strings.Contains(got[0], "az") {
t.Errorf("a token profile's checks %q", got)
}
if got := deniedChecks(profile{}, "Source IP address: 1.2.3.4 is blocked by Databricks IP ACL for workspace: 1"); !strings.Contains(got[0], "network") {
t.Errorf("IP ACL checks %q", got) t.Errorf("IP ACL checks %q", got)
} }