Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Scaleway Shell Plugin #314

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
138 changes: 138 additions & 0 deletions plugins/scaleway/api_key.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
package scaleway

import (
"context"
"os"

"github.com/1Password/shell-plugins/sdk"
"github.com/1Password/shell-plugins/sdk/importer"
"github.com/1Password/shell-plugins/sdk/provision"
"github.com/1Password/shell-plugins/sdk/schema"
"github.com/1Password/shell-plugins/sdk/schema/credname"
"github.com/1Password/shell-plugins/sdk/schema/fieldname"
)

func APIKey() schema.CredentialType {
return schema.CredentialType{
Name: credname.APIKey,
DocsURL: sdk.URL("https://www.scaleway.com/en/docs/identity-and-access-management/iam/how-to/create-api-keys"),
ManagementURL: sdk.URL("https://console.scaleway.com/iam/api-keys"),
Fields: []schema.CredentialField{
{
Name: fieldname.AccessKeyID,
MarkdownDescription: "The ID of the API Key used to authenticate to Scaleway.",
Secret: false,
Composition: &schema.ValueComposition{
Length: 20,
Prefix: "SCW",
Charset: schema.Charset{
Uppercase: true,
Digits: true,
},
},
},
{
Name: fieldname.SecretAccessKey,
MarkdownDescription: "The secret access key used to authenticate to Scaleway.",
Secret: true,
Composition: &schema.ValueComposition{
Length: 36,
Charset: schema.Charset{
Lowercase: true,
Digits: true,
Specific: []rune{'-'},
},
},
},
{
Name: fieldname.DefaultOrganization,

Check failure on line 48 in plugins/scaleway/api_key.go

View workflow job for this annotation

GitHub Actions / Test

undefined: fieldname.DefaultOrganization

Check failure on line 48 in plugins/scaleway/api_key.go

View workflow job for this annotation

GitHub Actions / Test

undefined: fieldname.DefaultOrganization

Check failure on line 48 in plugins/scaleway/api_key.go

View workflow job for this annotation

GitHub Actions / Lint

DefaultOrganization not declared by package fieldname (typecheck)

Check failure on line 48 in plugins/scaleway/api_key.go

View workflow job for this annotation

GitHub Actions / Lint

DefaultOrganization not declared by package fieldname (typecheck)
MarkdownDescription: "The default organization ID to use for this access key.",
Secret: false,
Composition: &schema.ValueComposition{
Length: 36,
Charset: schema.Charset{
Lowercase: true,
Digits: true,
Specific: []rune{'-'},
},
},
},
{
Name: fieldname.DefaultRegion,
MarkdownDescription: "The default region to use for this access key.",
Optional: true,
},
{
Name: fieldname.DefaultZone,

Check failure on line 66 in plugins/scaleway/api_key.go

View workflow job for this annotation

GitHub Actions / Test

undefined: fieldname.DefaultZone

Check failure on line 66 in plugins/scaleway/api_key.go

View workflow job for this annotation

GitHub Actions / Test

undefined: fieldname.DefaultZone

Check failure on line 66 in plugins/scaleway/api_key.go

View workflow job for this annotation

GitHub Actions / Lint

DefaultZone not declared by package fieldname (typecheck)

Check failure on line 66 in plugins/scaleway/api_key.go

View workflow job for this annotation

GitHub Actions / Lint

DefaultZone not declared by package fieldname (typecheck)
MarkdownDescription: "The default zone to use for this access key.",
Optional: true,
},
},
DefaultProvisioner: provision.EnvVars(defaultEnvVarMapping),
Importer: importer.TryAll(
importer.TryEnvVarPair(defaultEnvVarMapping),
TryScalewayConfigFile(),
)}
}

var defaultEnvVarMapping = map[string]sdk.FieldName{
"SCW_ACCESS_KEY": fieldname.AccessKeyID,
"SCW_SECRET_KEY": fieldname.SecretAccessKey,
"SCW_DEFAULT_ORGANIZATION_ID": fieldname.DefaultOrganization,

Check failure on line 81 in plugins/scaleway/api_key.go

View workflow job for this annotation

GitHub Actions / Test

undefined: fieldname.DefaultOrganization

Check failure on line 81 in plugins/scaleway/api_key.go

View workflow job for this annotation

GitHub Actions / Test

undefined: fieldname.DefaultOrganization

Check failure on line 81 in plugins/scaleway/api_key.go

View workflow job for this annotation

GitHub Actions / Lint

DefaultOrganization not declared by package fieldname (typecheck)

Check failure on line 81 in plugins/scaleway/api_key.go

View workflow job for this annotation

GitHub Actions / Lint

DefaultOrganization not declared by package fieldname (typecheck)
"SCW_DEFAULT_REGION": fieldname.DefaultRegion,
"SCW_DEFAULT_ZONE": fieldname.DefaultZone,

Check failure on line 83 in plugins/scaleway/api_key.go

View workflow job for this annotation

GitHub Actions / Test

undefined: fieldname.DefaultZone

Check failure on line 83 in plugins/scaleway/api_key.go

View workflow job for this annotation

GitHub Actions / Test

undefined: fieldname.DefaultZone

Check failure on line 83 in plugins/scaleway/api_key.go

View workflow job for this annotation

GitHub Actions / Lint

DefaultZone not declared by package fieldname (typecheck)

Check failure on line 83 in plugins/scaleway/api_key.go

View workflow job for this annotation

GitHub Actions / Lint

DefaultZone not declared by package fieldname (typecheck)
arunsathiya marked this conversation as resolved.
Show resolved Hide resolved
}

func TryScalewayConfigFile() sdk.Importer {
file := os.Getenv("SCW_CONFIG_PATH")
if file == "" {
file = "~/.config/scw/config.yaml"
}
return importer.TryFile(file, func(ctx context.Context, contents importer.FileContents, in sdk.ImportInput, out *sdk.ImportAttempt) {
var config Config
if err := contents.ToYAML(&config); err != nil {
out.AddError(err)
return
}

// TODO : Handle multiple profiles
accraw marked this conversation as resolved.
Show resolved Hide resolved

if config.AccessKey == "" || config.SecretKey == "" {
return
}

fields := make(map[sdk.FieldName]string)
fields[fieldname.AccessKeyID] = config.AccessKey
fields[fieldname.SecretAccessKey] = config.SecretKey
fields[fieldname.DefaultOrganization] = config.DefaultOrganizationID

Check failure on line 107 in plugins/scaleway/api_key.go

View workflow job for this annotation

GitHub Actions / Test

undefined: fieldname.DefaultOrganization

Check failure on line 107 in plugins/scaleway/api_key.go

View workflow job for this annotation

GitHub Actions / Test

undefined: fieldname.DefaultOrganization

Check failure on line 107 in plugins/scaleway/api_key.go

View workflow job for this annotation

GitHub Actions / Lint

DefaultOrganization not declared by package fieldname (typecheck)

Check failure on line 107 in plugins/scaleway/api_key.go

View workflow job for this annotation

GitHub Actions / Lint

DefaultOrganization not declared by package fieldname (typecheck)
accraw marked this conversation as resolved.
Show resolved Hide resolved
accraw marked this conversation as resolved.
Show resolved Hide resolved
if config.DefaultRegion != "" {
fields[fieldname.DefaultRegion] = config.DefaultRegion
}
if config.DefaultZone != "" {
fields[fieldname.DefaultZone] = config.DefaultZone

Check failure on line 112 in plugins/scaleway/api_key.go

View workflow job for this annotation

GitHub Actions / Test

undefined: fieldname.DefaultZone

Check failure on line 112 in plugins/scaleway/api_key.go

View workflow job for this annotation

GitHub Actions / Test

undefined: fieldname.DefaultZone

Check failure on line 112 in plugins/scaleway/api_key.go

View workflow job for this annotation

GitHub Actions / Lint

DefaultZone not declared by package fieldname (typecheck)

Check failure on line 112 in plugins/scaleway/api_key.go

View workflow job for this annotation

GitHub Actions / Lint

DefaultZone not declared by package fieldname (typecheck)
}
out.AddCandidate(sdk.ImportCandidate{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that Scaleway config file supports the concepts of profiles. Could we import the profile name as a Namehint? You'll need to set up at least two profiles to test the importer. Example:

profiles:
  first:
    access_key: redacted
    secret_key: redacted
    default_organization_id: redacted
    default_project_id: redacted
    default_zone: fr-par-1
    default_region: fr-par
    # api_url: https://api.scaleway.com
    # insecure: false

  second:
    access_key: redacted
    secret_key: redacted
    default_organization_id: redacted
    default_project_id: redacted
    default_zone: fr-par-1
    default_region: fr-par
    # api_url: https://api.scaleway.com
    # insecure: false

There's an example of how to import multiple profiles in the Fastly shell plugin.

Fields: fields,
})
})
}

type Config struct {
AccessKey string `yaml:"access_key"`
SecretKey string `yaml:"secret_key"`
DefaultOrganizationID string `yaml:"default_organization_id"`
DefaultProjectID string `yaml:"default_project_id"`
DefaultRegion string `yaml:"default_region"`
DefaultZone string `yaml:"default_zone"`
ActiveProfile string `yaml:"active_profile,omitempty"`
Profiles map[string]Profil `yaml:"profiles,omitempty"`
accraw marked this conversation as resolved.
Show resolved Hide resolved
}

type Profil struct {
accraw marked this conversation as resolved.
Show resolved Hide resolved
AccessKey string `yaml:"access_key"`
SecretKey string `yaml:"secret_key"`
DefaultOrganizationID string `yaml:"default_organization_id"`
DefaultProjectID string `yaml:"default_project_id"`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this attribute used anywhere?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed the same thing. @parthiv11, let's remove this since this is not being used anywhere. But before we do, would you know if the Scaleway CLI needs both the organization ID and the project ID to function?

DefaultZone string `yaml:"default_zone"`
DefaultRegion string `yaml:"default_region"`
}
79 changes: 79 additions & 0 deletions plugins/scaleway/api_key_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package scaleway

import (
"testing"

"github.com/1Password/shell-plugins/sdk"
"github.com/1Password/shell-plugins/sdk/plugintest"
"github.com/1Password/shell-plugins/sdk/schema/fieldname"
)

func TestAPIKeyImporter(t *testing.T) {
plugintest.TestImporter(t, APIKey().Importer, map[string]plugintest.ImportCase{
"Environment variables": {
Environment: map[string]string{
"SCW_ACCESS_KEY": "SCWSYXTFI97NSEXAMPLE",
"SCW_SECRET_KEY": "d9b67b48-873c-8ece-8270-e1e15example",
"SCW_DEFAULT_ORGANIZATION_ID": "11111111-2222-3333-4444-55555example",
arunsathiya marked this conversation as resolved.
Show resolved Hide resolved
},
ExpectedCandidates: []sdk.ImportCandidate{
{
Fields: map[sdk.FieldName]string{
fieldname.AccessKeyID: "SCWSYXTFI97NSEXAMPLE",
fieldname.SecretAccessKey: "d9b67b48-873c-8ece-8270-e1e15example",
fieldname.DefaultOrganization: "11111111-2222-3333-4444-55555example",

Check failure on line 24 in plugins/scaleway/api_key_test.go

View workflow job for this annotation

GitHub Actions / Test

undefined: fieldname.DefaultOrganization

Check failure on line 24 in plugins/scaleway/api_key_test.go

View workflow job for this annotation

GitHub Actions / Test

undefined: fieldname.DefaultOrganization
},
},
},
},
"SCW default config file location": {
Files: map[string]string{
"~/.config/scw/config.yaml": plugintest.LoadFixture(t, "simple.yaml"),
},
ExpectedCandidates: []sdk.ImportCandidate{
{
Fields: map[sdk.FieldName]string{
fieldname.AccessKeyID: "SCWSYXTFI97NSEXAMPLE",
fieldname.SecretAccessKey: "d9b67b48-873c-8ece-8270-e1e15example",
fieldname.DefaultOrganization: "11111111-2222-3333-4444-55555example",

Check failure on line 38 in plugins/scaleway/api_key_test.go

View workflow job for this annotation

GitHub Actions / Test

undefined: fieldname.DefaultOrganization

Check failure on line 38 in plugins/scaleway/api_key_test.go

View workflow job for this annotation

GitHub Actions / Test

undefined: fieldname.DefaultOrganization
},
},
},
},
"SCW config file with optional settings": {
Files: map[string]string{
"~/.config/scw/config.yaml": plugintest.LoadFixture(t, "optional.yaml"),
},
ExpectedCandidates: []sdk.ImportCandidate{
{
Fields: map[sdk.FieldName]string{
fieldname.AccessKeyID: "SCWSYXTFI97NSEXAMPLE",
fieldname.SecretAccessKey: "d9b67b48-873c-8ece-8270-e1e15example",
fieldname.DefaultOrganization: "11111111-2222-3333-4444-55555example",

Check failure on line 52 in plugins/scaleway/api_key_test.go

View workflow job for this annotation

GitHub Actions / Test

undefined: fieldname.DefaultOrganization

Check failure on line 52 in plugins/scaleway/api_key_test.go

View workflow job for this annotation

GitHub Actions / Test

undefined: fieldname.DefaultOrganization
fieldname.DefaultRegion: "fr-par",
fieldname.DefaultZone: "fr-par-1",

Check failure on line 54 in plugins/scaleway/api_key_test.go

View workflow job for this annotation

GitHub Actions / Test

undefined: fieldname.DefaultZone

Check failure on line 54 in plugins/scaleway/api_key_test.go

View workflow job for this annotation

GitHub Actions / Test

undefined: fieldname.DefaultZone
},
},
},
},
})
}

func TestAPIKeyProvisioner(t *testing.T) {
plugintest.TestProvisioner(t, APIKey().DefaultProvisioner, map[string]plugintest.ProvisionCase{
"default": {
ItemFields: map[sdk.FieldName]string{
fieldname.AccessKeyID: "SCWSYXTFI97NSEXAMPLE",
fieldname.SecretAccessKey: "d9b67b48-873c-8ece-8270-e1e15example",
fieldname.DefaultOrganization: "11111111-2222-3333-4444-55555example",
arunsathiya marked this conversation as resolved.
Show resolved Hide resolved
},
ExpectedOutput: sdk.ProvisionOutput{
Environment: map[string]string{
"SCW_ACCESS_KEY": "SCWSYXTFI97NSEXAMPLE",
"SCW_SECRET_KEY": "d9b67b48-873c-8ece-8270-e1e15example",
"SCW_DEFAULT_ORGANIZATION_ID": "11111111-2222-3333-4444-55555example",
},
},
},
})
}
22 changes: 22 additions & 0 deletions plugins/scaleway/plugin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package scaleway

import (
"github.com/1Password/shell-plugins/sdk"
"github.com/1Password/shell-plugins/sdk/schema"
)

func New() schema.Plugin {
return schema.Plugin{
Name: "scaleway",
Platform: schema.PlatformInfo{
Name: "Scaleway",
Homepage: sdk.URL("https://scaleway.com"),
},
Credentials: []schema.CredentialType{
APIKey(),
},
Executables: []schema.Executable{
ScalewayCLI(),
},
}
}
27 changes: 27 additions & 0 deletions plugins/scaleway/scw.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package scaleway

import (
"github.com/1Password/shell-plugins/sdk"
"github.com/1Password/shell-plugins/sdk/needsauth"
"github.com/1Password/shell-plugins/sdk/schema"
"github.com/1Password/shell-plugins/sdk/schema/credname"
)

func ScalewayCLI() schema.Executable {
return schema.Executable{
Name: "Scaleway CLI",
Runs: []string{"scw"},
DocsURL: sdk.URL("https://www.scaleway.com/en/cli"),
NeedsAuth: needsauth.IfAll(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's skip for -p as well, because that applies only when the configuration file exists on the computer. So, it's not relevant when a shell plugin is being used.

needsauth.NotForHelpOrVersion(),
needsauth.NotWithoutArgs(),
needsauth.NotWhenContainsArgs("-c"),
needsauth.NotWhenContainsArgs("--config"),
),
Uses: []schema.CredentialUsage{
{
Name: credname.APIKey,
},
},
}
}
6 changes: 6 additions & 0 deletions plugins/scaleway/test-fixtures/optional.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
access_key: SCWSYXTFI97NSEXAMPLE
secret_key: d9b67b48-873c-8ece-8270-e1e15example
default_organization_id: 11111111-2222-3333-4444-55555example
default_region: fr-par
default_zone: fr-par-1
3 changes: 3 additions & 0 deletions plugins/scaleway/test-fixtures/simple.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
access_key: SCWSYXTFI97NSEXAMPLE
secret_key: d9b67b48-873c-8ece-8270-e1e15example
default_organization_id: 11111111-2222-3333-4444-55555example
Loading