Skip to content

Commit 9c36de7

Browse files
Support specifying --image
1 parent 6c59f51 commit 9c36de7

File tree

4 files changed

+175
-62
lines changed

4 files changed

+175
-62
lines changed

.env.example

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,10 @@ AUTHGEAR_ONCE_PUBLIC_URL_SCHEME=https
2424

2525
# The Go template to generate an URL to download the authgear-once command.
2626
# The template is rendered with Uname_s and Uname_m.
27-
AUTHGEAR_ONCE_BINARY_DOWNLOAD_URL_GO_TEMPLATE='https://authgear.com?uname_s={{ $.Uname_s }}&uname_m={{ $.Uname_m }}'
27+
AUTHGEAR_ONCE_ONCE_COMMAND_DOWNLOAD_URL_GO_TEMPLATE='https://authgear.com?uname_s={{ $.Uname_s }}&uname_m={{ $.Uname_m }}'
28+
# Specify --image to the once command to override the image.
29+
# If not specified, no override is done.
30+
AUTHGEAR_ONCE_ONCE_COMMAND_IMAGE_OVERRIDE=
2831
AUTHGEAR_ONCE_KEYGEN_ENDPOINT=http://localhost:3000
2932
AUTHGEAR_ONCE_KEYGEN_ADMIN_TOKEN=
3033
AUTHGEAR_ONCE_KEYGEN_PRODUCT_ID=

cmd/cli/main.go

Lines changed: 35 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package main
22

33
import (
4-
"bytes"
54
"context"
65
"encoding/base64"
76
"encoding/json"
@@ -28,6 +27,7 @@ import (
2827

2928
"github.com/authgear/authgear-once-license-server/pkg/emailtemplate"
3029
"github.com/authgear/authgear-once-license-server/pkg/httpmiddleware"
30+
"github.com/authgear/authgear-once-license-server/pkg/installationscript"
3131
"github.com/authgear/authgear-once-license-server/pkg/keygen"
3232
"github.com/authgear/authgear-once-license-server/pkg/slogging"
3333
"github.com/authgear/authgear-once-license-server/pkg/smtp"
@@ -48,8 +48,6 @@ const indexHTML = `<!DOCTYPE html>
4848
</html>
4949
`
5050

51-
var installationShellScript *texttemplate.Template
52-
5351
var jsonResponseBadRequest = map[string]any{
5452
"error": map[string]any{
5553
"code": "bad_request",
@@ -82,32 +80,6 @@ var jsonResponseLicenseKeyExpired = map[string]any{
8280

8381
var jsonResponseOK = map[string]any{}
8482

85-
func init() {
86-
t, err := texttemplate.New("").Parse(`#!/bin/sh
87-
set -e
88-
89-
echo "Installing the Authgear ONCE command......"
90-
echo "This script uses sudo, you will be prompted for authentication."
91-
sudo true
92-
93-
download_url="{{ $.DownloadURL }}?uname_s=$(uname -s)&uname_m=$(uname -m)"
94-
tmp_path="$(mktemp)"
95-
curl -fsSL "$download_url" > "$tmp_path"
96-
sudo mv "$tmp_path" /usr/local/bin/authgear-once
97-
sudo chmod u+x /usr/local/bin/authgear-once
98-
99-
if [ "$(uname -s)" = "Darwin" ]; then
100-
/usr/local/bin/authgear-once setup "{{ $.LicenseKey }}"
101-
else
102-
sudo /usr/local/bin/authgear-once setup "{{ $.LicenseKey }}"
103-
fi
104-
`)
105-
if err != nil {
106-
panic(err)
107-
}
108-
installationShellScript = t
109-
}
110-
11183
var rootCmd = &cobra.Command{
11284
Use: "authgear-once-license-server",
11385
}
@@ -148,12 +120,11 @@ var serveCmd = &cobra.Command{
148120

149121
u := ConstructFullURL(r)
150122

151-
data := map[string]any{
152-
"DownloadURL": u.String(),
153-
"LicenseKey": licenseKey,
154-
}
155-
var buf bytes.Buffer
156-
err = installationShellScript.Execute(&buf, data)
123+
script, err := installationscript.Render(installationscript.RenderOptions{
124+
DownloadURL: u.String(),
125+
LicenseKey: licenseKey,
126+
ImageOverride: deps.AUTHGEAR_ONCE_ONCE_COMMAND_IMAGE_OVERRIDE,
127+
})
157128
if err != nil {
158129
slogging.Error(ctx, logger, "failed to render installation shell script",
159130
"error", err)
@@ -163,17 +134,17 @@ var serveCmd = &cobra.Command{
163134

164135
w.Header().Set("Content-Type", "text/plain")
165136
w.Header().Set("Cache-Control", "no-store")
166-
w.Write(buf.Bytes())
137+
w.Write([]byte(script))
167138
default:
168-
// Otherwise, we return 303 to download the binary.
139+
// Otherwise, we return 303 to download the executable.
169140
uname_s = uname.NormalizeUnameS(uname_s)
170141
uname_m = uname.NormalizeUnameM(uname_m)
171142
data := map[string]any{
172143
"Uname_s": uname_s,
173144
"Uname_m": uname_m,
174145
}
175146
var buf strings.Builder
176-
err = deps.AuthgearOnceDownloadURLGoTemplate.Execute(&buf, data)
147+
err = deps.AUTHGEAR_ONCE_ONCE_COMMAND_DOWNLOAD_URL_GO_TEMPLATE.Execute(&buf, data)
177148
if err != nil {
178149
slogging.Error(ctx, logger, "failed to render download url",
179150
"error", err)
@@ -418,24 +389,25 @@ type dependenciesKeyType struct{}
418389
var dependenciesKey = dependenciesKeyType{}
419390

420391
type Dependencies struct {
421-
HTTPClient *http.Client
422-
StripeClient *client.API
423-
SMTPDialer *gomail.Dialer
424-
SMTPSender string
425-
StripeCheckoutSessionSuccessURL string
426-
StripeCheckoutSessionCancelURL string
427-
StripeCheckoutSessionPriceID string
428-
StripeWebhookSigningSecret string
429-
PublicURLScheme string
430-
AuthgearOnceDownloadURLGoTemplate *texttemplate.Template
431-
KeygenConfig keygen.KeygenConfig
392+
HTTPClient *http.Client
393+
StripeClient *client.API
394+
SMTPDialer *gomail.Dialer
395+
SMTPSender string
396+
StripeCheckoutSessionSuccessURL string
397+
StripeCheckoutSessionCancelURL string
398+
StripeCheckoutSessionPriceID string
399+
StripeWebhookSigningSecret string
400+
AUTHGEAR_ONCE_PUBLIC_URL_SCHEME string
401+
AUTHGEAR_ONCE_ONCE_COMMAND_DOWNLOAD_URL_GO_TEMPLATE *texttemplate.Template
402+
AUTHGEAR_ONCE_ONCE_COMMAND_IMAGE_OVERRIDE string
403+
KeygenConfig keygen.KeygenConfig
432404
}
433405

434406
func ConstructFullURL(r *http.Request) *url.URL {
435407
ctx := r.Context()
436408
deps := GetDependencies(ctx)
437409
scheme := "https"
438-
if deps.PublicURLScheme == "http" {
410+
if deps.AUTHGEAR_ONCE_PUBLIC_URL_SCHEME == "http" {
439411
scheme = "http"
440412
}
441413
host := r.Host
@@ -491,22 +463,24 @@ func main() {
491463
SMTPPassword: os.Getenv("AUTHGEAR_ONCE_SMTP_PASSWORD"),
492464
})
493465

494-
authgearOnceDownloadURLGoTemplate, err := texttemplate.New("").Parse(os.Getenv("AUTHGEAR_ONCE_BINARY_DOWNLOAD_URL_GO_TEMPLATE"))
466+
AUTHGEAR_ONCE_ONCE_COMMAND_DOWNLOAD_URL_GO_TEMPLATE, err := texttemplate.New("").Parse(os.Getenv("AUTHGEAR_ONCE_ONCE_COMMAND_DOWNLOAD_URL_GO_TEMPLATE"))
495467
if err != nil {
496468
panic(err)
497469
}
470+
AUTHGEAR_ONCE_ONCE_COMMAND_IMAGE_OVERRIDE := os.Getenv("AUTHGEAR_ONCE_ONCE_COMMAND_IMAGE_OVERRIDE")
498471

499472
dependencies := Dependencies{
500-
HTTPClient: &http.Client{},
501-
StripeClient: stripeClient,
502-
SMTPDialer: smtpDialer,
503-
SMTPSender: os.Getenv("AUTHGEAR_ONCE_SMTP_SENDER"),
504-
StripeCheckoutSessionSuccessURL: os.Getenv("AUTHGEAR_ONCE_STRIPE_CHECKOUT_SESSION_SUCCESS_URL"),
505-
StripeCheckoutSessionCancelURL: os.Getenv("AUTHGEAR_ONCE_STRIPE_CHECKOUT_SESSION_CANCEL_URL"),
506-
StripeCheckoutSessionPriceID: os.Getenv("AUTHGEAR_ONCE_STRIPE_CHECKOUT_SESSION_PRICE_ID"),
507-
StripeWebhookSigningSecret: os.Getenv("AUTHGEAR_ONCE_STRIPE_WEBHOOK_SIGNING_SECRET"),
508-
PublicURLScheme: os.Getenv("AUTHGEAR_ONCE_PUBLIC_URL_SCHEME"),
509-
AuthgearOnceDownloadURLGoTemplate: authgearOnceDownloadURLGoTemplate,
473+
HTTPClient: &http.Client{},
474+
StripeClient: stripeClient,
475+
SMTPDialer: smtpDialer,
476+
SMTPSender: os.Getenv("AUTHGEAR_ONCE_SMTP_SENDER"),
477+
StripeCheckoutSessionSuccessURL: os.Getenv("AUTHGEAR_ONCE_STRIPE_CHECKOUT_SESSION_SUCCESS_URL"),
478+
StripeCheckoutSessionCancelURL: os.Getenv("AUTHGEAR_ONCE_STRIPE_CHECKOUT_SESSION_CANCEL_URL"),
479+
StripeCheckoutSessionPriceID: os.Getenv("AUTHGEAR_ONCE_STRIPE_CHECKOUT_SESSION_PRICE_ID"),
480+
StripeWebhookSigningSecret: os.Getenv("AUTHGEAR_ONCE_STRIPE_WEBHOOK_SIGNING_SECRET"),
481+
AUTHGEAR_ONCE_PUBLIC_URL_SCHEME: os.Getenv("AUTHGEAR_ONCE_PUBLIC_URL_SCHEME"),
482+
AUTHGEAR_ONCE_ONCE_COMMAND_DOWNLOAD_URL_GO_TEMPLATE: AUTHGEAR_ONCE_ONCE_COMMAND_DOWNLOAD_URL_GO_TEMPLATE,
483+
AUTHGEAR_ONCE_ONCE_COMMAND_IMAGE_OVERRIDE: AUTHGEAR_ONCE_ONCE_COMMAND_IMAGE_OVERRIDE,
510484
KeygenConfig: keygen.KeygenConfig{
511485
Endpoint: os.Getenv("AUTHGEAR_ONCE_KEYGEN_ENDPOINT"),
512486
AdminToken: os.Getenv("AUTHGEAR_ONCE_KEYGEN_ADMIN_TOKEN"),
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package installationscript
2+
3+
import (
4+
"bytes"
5+
texttemplate "text/template"
6+
)
7+
8+
var tmpl *texttemplate.Template
9+
10+
func init() {
11+
t, err := texttemplate.New("").Parse(`#!/bin/sh
12+
set -e
13+
14+
echo "Installing the Authgear ONCE command......"
15+
echo "This script uses sudo, you will be prompted for authentication."
16+
sudo true
17+
18+
download_url="{{ $.DownloadURL }}?uname_s=$(uname -s)&uname_m=$(uname -m)"
19+
tmp_path="$(mktemp)"
20+
curl -fsSL "$download_url" > "$tmp_path"
21+
sudo mv "$tmp_path" /usr/local/bin/authgear-once
22+
sudo chmod u+x /usr/local/bin/authgear-once
23+
24+
{{- $image := "" }}
25+
{{- if $.ImageOverride }}
26+
{{- $image = printf "--image '%v'" $.ImageOverride }}
27+
{{- end }}
28+
29+
if [ "$(uname -s)" = "Darwin" ]; then
30+
/usr/local/bin/authgear-once setup {{ $image }} "{{ $.LicenseKey }}"
31+
else
32+
sudo /usr/local/bin/authgear-once setup {{ $image }} "{{ $.LicenseKey }}"
33+
fi
34+
`)
35+
if err != nil {
36+
panic(err)
37+
}
38+
tmpl = t
39+
}
40+
41+
type RenderOptions struct {
42+
DownloadURL string
43+
LicenseKey string
44+
ImageOverride string
45+
}
46+
47+
func Render(opts RenderOptions) (out string, err error) {
48+
var buf bytes.Buffer
49+
err = tmpl.Execute(&buf, opts)
50+
if err != nil {
51+
return
52+
}
53+
54+
out = buf.String()
55+
return
56+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package installationscript
2+
3+
import (
4+
"testing"
5+
)
6+
7+
func TestRender(t *testing.T) {
8+
tests := []struct {
9+
name string
10+
opts RenderOptions
11+
expected string
12+
}{
13+
{
14+
name: "Without --image",
15+
opts: RenderOptions{
16+
DownloadURL: "https://example.com/download",
17+
LicenseKey: "license-123",
18+
},
19+
expected: `#!/bin/sh
20+
set -e
21+
22+
echo "Installing the Authgear ONCE command......"
23+
echo "This script uses sudo, you will be prompted for authentication."
24+
sudo true
25+
26+
download_url="https://example.com/download?uname_s=$(uname -s)&uname_m=$(uname -m)"
27+
tmp_path="$(mktemp)"
28+
curl -fsSL "$download_url" > "$tmp_path"
29+
sudo mv "$tmp_path" /usr/local/bin/authgear-once
30+
sudo chmod u+x /usr/local/bin/authgear-once
31+
32+
if [ "$(uname -s)" = "Darwin" ]; then
33+
/usr/local/bin/authgear-once setup "license-123"
34+
else
35+
sudo /usr/local/bin/authgear-once setup "license-123"
36+
fi
37+
`,
38+
},
39+
{
40+
name: "With --image",
41+
opts: RenderOptions{
42+
DownloadURL: "https://example.com/download",
43+
LicenseKey: "license-abc",
44+
ImageOverride: "some-docker-registry.com/authgear-once:1.0.0",
45+
},
46+
expected: `#!/bin/sh
47+
set -e
48+
49+
echo "Installing the Authgear ONCE command......"
50+
echo "This script uses sudo, you will be prompted for authentication."
51+
sudo true
52+
53+
download_url="https://example.com/download?uname_s=$(uname -s)&uname_m=$(uname -m)"
54+
tmp_path="$(mktemp)"
55+
curl -fsSL "$download_url" > "$tmp_path"
56+
sudo mv "$tmp_path" /usr/local/bin/authgear-once
57+
sudo chmod u+x /usr/local/bin/authgear-once
58+
59+
if [ "$(uname -s)" = "Darwin" ]; then
60+
/usr/local/bin/authgear-once setup --image 'some-docker-registry.com/authgear-once:1.0.0' "license-abc"
61+
else
62+
sudo /usr/local/bin/authgear-once setup --image 'some-docker-registry.com/authgear-once:1.0.0' "license-abc"
63+
fi
64+
`,
65+
},
66+
}
67+
68+
for _, tt := range tests {
69+
t.Run(tt.name, func(t *testing.T) {
70+
result, err := Render(tt.opts)
71+
if err != nil {
72+
t.Fatalf("Render() error = %v", err)
73+
}
74+
75+
if result != tt.expected {
76+
t.Errorf("Render() output mismatch\nGot:\n%s\nWant:\n%s", result, tt.expected)
77+
}
78+
})
79+
}
80+
}

0 commit comments

Comments
 (0)