Skip to content

Commit cf16c68

Browse files
committed
feat: add localxpose loclx cli
1 parent 61135fa commit cf16c68

5 files changed

Lines changed: 199 additions & 0 deletions

File tree

‎plugins/localxpose/access_token.go‎

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package localxpose
2+
3+
import (
4+
"context"
5+
6+
"github.com/99designs/keyring"
7+
8+
"github.com/1Password/shell-plugins/sdk"
9+
"github.com/1Password/shell-plugins/sdk/importer"
10+
"github.com/1Password/shell-plugins/sdk/provision"
11+
"github.com/1Password/shell-plugins/sdk/schema"
12+
"github.com/1Password/shell-plugins/sdk/schema/credname"
13+
"github.com/1Password/shell-plugins/sdk/schema/fieldname"
14+
)
15+
16+
const (
17+
serviceName = "https://loclx.io"
18+
keyringKeyName = "token"
19+
tokenFilePath = "~/.localxpose/.access"
20+
)
21+
22+
func AccessToken() schema.CredentialType {
23+
return schema.CredentialType{
24+
Name: credname.AccessToken,
25+
DocsURL: sdk.URL("https://localxpose.io/docs"),
26+
ManagementURL: sdk.URL("https://localxpose.io/dashboard/access"),
27+
Fields: []schema.CredentialField{
28+
{
29+
Name: fieldname.AccessToken,
30+
MarkdownDescription: "Token used to authenticate to LocalXpose.",
31+
Secret: true,
32+
},
33+
},
34+
DefaultProvisioner: provision.EnvVars(defaultEnvVarMapping),
35+
Importer: importer.TryAll(
36+
importer.TryEnvVarPair(defaultEnvVarMapping),
37+
TryOSKeyring(),
38+
TryAccessTokenFile(),
39+
)}
40+
}
41+
42+
var defaultEnvVarMapping = map[string]sdk.FieldName{
43+
"LX_ACCESS_TOKEN": fieldname.AccessToken,
44+
}
45+
46+
func TryAccessTokenFile() sdk.Importer {
47+
return importer.TryFile(tokenFilePath, func(ctx context.Context, contents importer.FileContents, in sdk.ImportInput, out *sdk.ImportAttempt) {
48+
if contents.ToString() == "" {
49+
return
50+
}
51+
out.AddCandidate(sdk.ImportCandidate{
52+
Fields: map[sdk.FieldName]string{
53+
fieldname.AccessToken: contents.ToString(),
54+
},
55+
})
56+
})
57+
}
58+
59+
func TryOSKeyring() sdk.Importer {
60+
return func(ctx context.Context, in sdk.ImportInput, out *sdk.ImportOutput) {
61+
availableBackends := keyring.AvailableBackends()
62+
if len(availableBackends) == 0 {
63+
return
64+
}
65+
for _, backendType := range availableBackends {
66+
attempt := out.NewAttempt(importer.SourceOther(string(backendType), ""))
67+
openKeyring, err := keyring.Open(keyring.Config{
68+
KeychainTrustApplication: true,
69+
ServiceName: serviceName,
70+
})
71+
if err != nil {
72+
attempt.AddError(err)
73+
return
74+
}
75+
key, err := openKeyring.Get(keyringKeyName)
76+
if err != nil {
77+
attempt.AddError(err)
78+
continue
79+
}
80+
attempt.AddCandidate(sdk.ImportCandidate{
81+
Fields: map[sdk.FieldName]string{
82+
fieldname.AccessToken: string(key.Data),
83+
},
84+
})
85+
}
86+
}
87+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package localxpose
2+
3+
import (
4+
"testing"
5+
6+
"github.com/1Password/shell-plugins/sdk"
7+
"github.com/1Password/shell-plugins/sdk/plugintest"
8+
"github.com/1Password/shell-plugins/sdk/schema/fieldname"
9+
)
10+
11+
func TestAccessTokenProvisioner(t *testing.T) {
12+
plugintest.TestProvisioner(t, AccessToken().DefaultProvisioner, map[string]plugintest.ProvisionCase{
13+
"default": {
14+
ItemFields: map[sdk.FieldName]string{
15+
fieldname.AccessToken: "PROVISIONERqLtcqQ8a3oRVfK5tiHzDOhEXAMPLE",
16+
},
17+
ExpectedOutput: sdk.ProvisionOutput{
18+
Environment: map[string]string{
19+
"LX_ACCESS_TOKEN": "PROVISIONERqLtcqQ8a3oRVfK5tiHzDOhEXAMPLE",
20+
},
21+
},
22+
},
23+
})
24+
}
25+
26+
func TestAccessTokenImporter(t *testing.T) {
27+
expectedFields := map[sdk.FieldName]string{
28+
fieldname.AccessToken: "31QJpgl8FB9qLtcqQ8a3oRVfK5tiHzDOhEXAMPLE",
29+
}
30+
31+
plugintest.TestImporter(t, AccessToken().Importer, map[string]plugintest.ImportCase{
32+
"environment": {
33+
Environment: map[string]string{
34+
"LX_ACCESS_TOKEN": "31QJpgl8FB9qLtcqQ8a3oRVfK5tiHzDOhEXAMPLE",
35+
},
36+
ExpectedCandidates: []sdk.ImportCandidate{
37+
{
38+
Fields: expectedFields,
39+
},
40+
},
41+
},
42+
"file": {
43+
Files: map[string]string{
44+
"~/.localxpose/.access": plugintest.LoadFixture(t, "localxpose.access"),
45+
},
46+
ExpectedCandidates: []sdk.ImportCandidate{
47+
{
48+
Fields: expectedFields,
49+
},
50+
},
51+
},
52+
})
53+
}

‎plugins/localxpose/localxpose.go‎

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package localxpose
2+
3+
import (
4+
"github.com/1Password/shell-plugins/sdk"
5+
"github.com/1Password/shell-plugins/sdk/needsauth"
6+
"github.com/1Password/shell-plugins/sdk/schema"
7+
"github.com/1Password/shell-plugins/sdk/schema/credname"
8+
)
9+
10+
func LocalXposeCLI() schema.Executable {
11+
return schema.Executable{
12+
Name: "LocalXpose CLI",
13+
Runs: []string{"loclx"},
14+
DocsURL: sdk.URL("https://localxpose.io/docs/cli"),
15+
NeedsAuth: needsauth.IfAll(
16+
needsauth.NotForHelpOrVersion(),
17+
needsauth.NotWhenContainsArgs("account", "login"), // skip 1Password authentication for "loclx account login" and its subcommands
18+
needsauth.NotWhenContainsArgs("a", "login"), // skip 1Password authentication for "loclx account login" and its subcommands
19+
needsauth.NotWhenContainsArgs("account", "logout"), // skip 1Password authentication for "loclx account logout" and its subcommands
20+
needsauth.NotWhenContainsArgs("a", "logout"), // skip 1Password authentication for "loclx account logout" and its subcommands
21+
needsauth.NotWhenContainsArgs("service", "restart"), // skip 1Password authentication for "loclx service restart" and its subcommands
22+
needsauth.NotWhenContainsArgs("service", "start"), // skip 1Password authentication for "loclx service start" and its subcommands
23+
needsauth.NotWhenContainsArgs("service", "status"), // skip 1Password authentication for "loclx service status" and its subcommands
24+
needsauth.NotWhenContainsArgs("service", "stop"), // skip 1Password authentication for "loclx service stop" and its subcommands
25+
needsauth.NotWhenContainsArgs("service", "uninstall"), // skip 1Password authentication for "loclx service uninstall" and its subcommands
26+
needsauth.NotWhenContainsArgs("setting"), // skip 1Password authentication for "loclx setting" and its subcommands
27+
needsauth.NotWhenContainsArgs("update"), // skip 1Password authentication for "loclx update" and its subcommands
28+
needsauth.NotWithoutArgs(),
29+
),
30+
Uses: []schema.CredentialUsage{
31+
{
32+
Name: credname.AccessToken,
33+
},
34+
},
35+
}
36+
}

‎plugins/localxpose/plugin.go‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package localxpose
2+
3+
import (
4+
"github.com/1Password/shell-plugins/sdk"
5+
"github.com/1Password/shell-plugins/sdk/schema"
6+
)
7+
8+
func New() schema.Plugin {
9+
return schema.Plugin{
10+
Name: "localxpose",
11+
Platform: schema.PlatformInfo{
12+
Name: "LocalXpose",
13+
Homepage: sdk.URL("https://localxpose.io"),
14+
},
15+
Credentials: []schema.CredentialType{
16+
AccessToken(),
17+
},
18+
Executables: []schema.Executable{
19+
LocalXposeCLI(),
20+
},
21+
}
22+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
31QJpgl8FB9qLtcqQ8a3oRVfK5tiHzDOhEXAMPLE

0 commit comments

Comments
 (0)