Skip to content

Commit

Permalink
add setup instructions for remoteapis
Browse files Browse the repository at this point in the history
  • Loading branch information
malt3 committed Feb 22, 2025
1 parent 0815c45 commit 46438bf
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 15 deletions.
51 changes: 51 additions & 0 deletions authenticate/internal/lookupchain/lookupchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,25 @@ func (c *LookupChain) Lookup(binding string) (string, error) {
return "", fmt.Errorf("no value found for binding %q after querying %v", binding, strings.Join(sourceNames, ", "))
}

func (c *LookupChain) SetupInstructions(binding, meaning string) string {
if len(c.config) == 0 {
return fmt.Sprintf("No sources are configured to look up the secret with binding name %s. Refer to the documentation related to configuration files for more information.", binding)
}
instructions := []string{fmt.Sprintf("Instructions for setting up the secret with binding name %q (%s):", binding, meaning)}
for i, entry := range c.config {
source, err := c.sourceFor(entry)
if err != nil {
instructions = append(instructions, fmt.Sprintf("failed to lookup instuctions for entry %d: %v", i, err))
continue
}
instruction, ok := source.SetupInstructions(binding)
if ok {
instructions = append(instructions, instruction)
}
}
return strings.Join(instructions, "\n")
}

func (c *LookupChain) sourceFor(entry ConfigEntry) (Source, error) {
decoder := json.NewDecoder(bytes.NewReader(entry.RawMessage))
decoder.DisallowUnknownFields()
Expand Down Expand Up @@ -91,6 +110,7 @@ type ConfigEntry struct {
type Source interface {
Lookup(binding string) (string, error)
Canonicalize()
SetupInstructions(binding string) (string, bool)
}

type Env struct {
Expand Down Expand Up @@ -122,6 +142,21 @@ func (e *Env) Canonicalize() {
}
}

func (e *Env) SetupInstructions(binding string) (string, bool) {
if e.Binding != binding {
return "", false
}
_, success := os.LookupEnv(e.Name)
var status string
if success {
status = "SET"
} else {
status = "NOT SET"
}

return fmt.Sprintf(" - Export the environment variable %s (status: %s)", e.Name, status), true
}

type Keyring struct {
// Source is the name of the source used to look up the secret.
// It must be "keyring".
Expand Down Expand Up @@ -154,6 +189,22 @@ func (k *Keyring) Canonicalize() {
}
}

func (e *Keyring) SetupInstructions(binding string) (string, bool) {
if e.Binding != binding {
return "", false
}
_, getErr := keyring.Get(e.Service, "")
var status string
if errors.Is(getErr, keyring.ErrNotFound) {
status = "NOT SET"
} else {
status = "SET"
}

return fmt.Sprintf(` - Add the secret to the system keyring under the %s service name (status: %s):
$ %s setup-keyring -f secret.txt %s`, e.Service, status, os.Args[0], e.Service), true
}

// Default constructs a partially marshalled Config from a slice of specific config entries.
func Default(in []Source) Config {
out := make(Config, len(in))
Expand Down
55 changes: 40 additions & 15 deletions authenticate/remoteapis/remoteapis.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,27 @@ func (g *RemoteAPIs) CacheKey(req api.GetCredentialsRequest) string {
return req.URI
}

func (g *RemoteAPIs) SetupInstructionsForURI(ctx context.Context, uri string) string {
var lookupChainInstructions string
cfg, err := configFromContext(ctx)
if err == nil {
chain := lookupchain.New(cfg.LookupChain)
lookupChainInstructions = chain.SetupInstructions("default", "secret sent to remote APIs as an authentication token or basic auth credentials")
} else {
lookupChainInstructions = fmt.Sprintf("due to a configuration parsing issue, no further setup instructions are available: %v", err)
}

var rbeSystemInstructions string
switch {
case strings.HasPrefix(uri, "https://remote.buildbuddy.io/"):
rbeSystemInstructions = `For BuildBuddy, visit https://app.buildbuddy.io/docs/setup/ and copy the secret after "x-buildbuddy-api-key=". Use the header_name "x-buildbuddy-api-key" in the configuration.`
default:
rbeSystemInstructions = "Cannot infer RBE provider based on uri. Skipping provider-specific setup instructions."
}

return fmt.Sprintf("%s refers to a remote build execution (RBE) system (a gRPC endpoint used for remote execution, remote caching, or related purposes).\n%s\n\n%s", uri, rbeSystemInstructions, lookupChainInstructions)
}

func (RemoteAPIs) Resolver(ctx context.Context) (api.Resolver, error) {
return &RemoteAPIs{}, nil
}
Expand All @@ -42,21 +63,7 @@ func (RemoteAPIs) Resolver(ctx context.Context) (api.Resolver, error) {
//
// https://github.com/EngFlow/credential-helper-spec/blob/main/spec.md#get
func (g *RemoteAPIs) Get(ctx context.Context, req api.GetCredentialsRequest) (api.GetCredentialsResponse, error) {
cfg, err := helperconfig.FromContext(ctx, configFragment{
AuthMethod: "header",
LookupChain: lookupchain.Default([]lookupchain.Source{
&lookupchain.Env{
Source: "env",
Name: "CREDENTIAL_HELPER_REMOTEAPIS_SECRET",
Binding: "default",
},
&lookupchain.Keyring{
Source: "keyring",
Service: "tweag-credential-helper:remoteapis",
Binding: "default",
},
}),
})
cfg, err := configFromContext(ctx)
if err != nil {
return api.GetCredentialsResponse{}, fmt.Errorf("getting configuration fragment for remotapis helper and url %s: %w", req.URI, err)
}
Expand Down Expand Up @@ -152,3 +159,21 @@ type configFragment struct {
// It defaults to the sources "env", "keyring".
LookupChain lookupchain.Config `json:"lookup_chain"`
}

func configFromContext(ctx context.Context) (configFragment, error) {
return helperconfig.FromContext(ctx, configFragment{
AuthMethod: "header",
LookupChain: lookupchain.Default([]lookupchain.Source{
&lookupchain.Env{
Source: "env",
Name: "CREDENTIAL_HELPER_REMOTEAPIS_SECRET",
Binding: "default",
},
&lookupchain.Keyring{
Source: "keyring",
Service: "tweag-credential-helper:remoteapis",
Binding: "default",
},
}),
})
}

0 comments on commit 46438bf

Please sign in to comment.