create-svc 0.1.10 → 0.1.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -43
- package/bin/create-service.mjs +2 -0
- package/package.json +12 -9
- package/src/cli.test.ts +28 -10
- package/src/cli.ts +195 -30
- package/src/git-bootstrap.test.ts +40 -0
- package/src/git-bootstrap.ts +110 -0
- package/src/naming.test.ts +1 -0
- package/src/naming.ts +23 -0
- package/src/post-scaffold.test.ts +19 -0
- package/src/post-scaffold.ts +17 -4
- package/src/profiles.ts +2 -5
- package/src/scaffold.test.ts +231 -40
- package/src/scaffold.ts +84 -29
- package/src/vault.test.ts +61 -1
- package/src/vault.ts +77 -15
- package/templates/shared/.github/workflows/ci.yml +2 -1
- package/templates/shared/.github/workflows/deploy.yml +2 -0
- package/templates/shared/README.md +124 -47
- package/templates/shared/grafana/alerts.yaml +54 -0
- package/templates/shared/grafana/waitlist-dashboard.json +63 -0
- package/templates/shared/scripts/authctl.ts +231 -0
- package/templates/shared/scripts/cloudrun/bootstrap.ts +14 -5
- package/templates/shared/scripts/cloudrun/cleanup.ts +64 -4
- package/templates/shared/scripts/cloudrun/cli.ts +324 -7
- package/templates/shared/scripts/cloudrun/config.ts +11 -4
- package/templates/shared/scripts/cloudrun/deploy.ts +0 -4
- package/templates/shared/scripts/cloudrun/lib.ts +174 -41
- package/templates/shared/scripts/cloudrun/neon.ts +45 -0
- package/templates/shared/scripts/dev.ts +22 -0
- package/templates/shared/scripts/ensure-local-db.ts +3 -0
- package/templates/shared/scripts/local-docker.ts +63 -0
- package/templates/shared/scripts/local-env.ts +27 -0
- package/templates/shared/scripts/seed.ts +73 -0
- package/templates/shared/scripts/wait-for-db.ts +32 -0
- package/templates/shared/service.config.ts +59 -0
- package/templates/shared/service.yaml +24 -44
- package/templates/targets/workers/.github/workflows/ci.yml +19 -0
- package/templates/targets/workers/.github/workflows/deploy.yml +19 -0
- package/templates/targets/workers/Makefile +33 -0
- package/templates/targets/workers/README.md +75 -0
- package/templates/targets/workers/package.json +35 -0
- package/templates/targets/workers/scripts/workers/cli.ts +397 -0
- package/templates/targets/workers/src/auth.ts +178 -0
- package/templates/targets/workers/src/index.ts +198 -0
- package/templates/targets/workers/src/storage.ts +370 -0
- package/templates/targets/workers/test/app.test.ts +108 -0
- package/templates/targets/workers/tsconfig.json +11 -0
- package/templates/targets/workers/wrangler.toml +24 -0
- package/templates/variants/bun-connectrpc/Makefile +14 -8
- package/templates/variants/bun-connectrpc/gen/protos/waitlist/v1/waitlist_pb.ts +424 -0
- package/templates/variants/bun-connectrpc/migrations/0000_init.sql +12 -55
- package/templates/variants/bun-connectrpc/package.json +12 -5
- package/templates/variants/bun-connectrpc/protos/waitlist/v1/waitlist.proto +91 -0
- package/templates/variants/bun-connectrpc/scripts/codegen.ts +1 -1
- package/templates/variants/bun-connectrpc/scripts/migrate.ts +4 -1
- package/templates/variants/bun-connectrpc/src/auth.ts +200 -0
- package/templates/variants/bun-connectrpc/src/db/repository.ts +67 -420
- package/templates/variants/bun-connectrpc/src/db/schema.ts +15 -64
- package/templates/variants/bun-connectrpc/src/index.ts +76 -176
- package/templates/variants/bun-connectrpc/src/temporal/activities.ts +14 -0
- package/templates/variants/bun-connectrpc/src/temporal/worker.ts +38 -0
- package/templates/variants/bun-connectrpc/src/temporal/workflows.ts +10 -0
- package/templates/variants/bun-connectrpc/src/waitlist/service.ts +172 -0
- package/templates/variants/bun-connectrpc/src/waitlist/types.ts +45 -0
- package/templates/variants/bun-connectrpc/test/app.test.ts +4 -4
- package/templates/variants/bun-connectrpc/test/waitlist.integration.test.ts +71 -0
- package/templates/variants/bun-hono/Makefile +14 -8
- package/templates/variants/bun-hono/migrations/0000_init.sql +12 -55
- package/templates/variants/bun-hono/package.json +12 -5
- package/templates/variants/bun-hono/scripts/migrate.ts +4 -1
- package/templates/variants/bun-hono/src/auth.ts +181 -0
- package/templates/variants/bun-hono/src/db/repository.ts +68 -421
- package/templates/variants/bun-hono/src/db/schema.ts +15 -64
- package/templates/variants/bun-hono/src/index.ts +65 -180
- package/templates/variants/bun-hono/src/temporal/activities.ts +14 -0
- package/templates/variants/bun-hono/src/temporal/worker.ts +38 -0
- package/templates/variants/bun-hono/src/temporal/workflows.ts +10 -0
- package/templates/variants/bun-hono/src/waitlist/service.ts +166 -0
- package/templates/variants/bun-hono/src/waitlist/types.ts +50 -0
- package/templates/variants/bun-hono/test/app.test.ts +72 -41
- package/templates/variants/bun-hono/test/waitlist.integration.test.ts +102 -0
- package/templates/variants/go-chi/Makefile +27 -11
- package/templates/variants/go-chi/atlas.hcl +8 -0
- package/templates/variants/go-chi/cmd/server/main.go +21 -10
- package/templates/variants/go-chi/go.mod +1 -3
- package/templates/variants/go-chi/internal/app/service.go +202 -685
- package/templates/variants/go-chi/internal/auth/middleware.go +289 -0
- package/templates/variants/go-chi/internal/auth/middleware_test.go +38 -0
- package/templates/variants/go-chi/internal/config/config.go +27 -11
- package/templates/variants/go-chi/internal/httpapi/routes.go +78 -157
- package/templates/variants/go-chi/internal/httpapi/waitlist_integration_test.go +199 -0
- package/templates/variants/go-chi/internal/temporal/activities.go +27 -0
- package/templates/variants/go-chi/internal/temporal/worker.go +42 -0
- package/templates/variants/go-chi/internal/temporal/workflows.go +18 -0
- package/templates/variants/go-chi/migrations/0000_init.sql +12 -55
- package/templates/variants/go-chi/migrations/atlas.sum +2 -0
- package/templates/variants/go-chi/package.json +7 -1
- package/templates/variants/go-connectrpc/Makefile +26 -9
- package/templates/variants/go-connectrpc/atlas.hcl +8 -0
- package/templates/variants/go-connectrpc/buf.gen.yaml +2 -2
- package/templates/variants/go-connectrpc/cmd/server/main.go +23 -12
- package/templates/variants/go-connectrpc/gen/waitlist/v1/waitlist.pb.go +960 -0
- package/templates/variants/go-connectrpc/gen/waitlist/v1/waitlistv1connect/waitlist.connect.go +283 -0
- package/templates/variants/go-connectrpc/go.mod +1 -1
- package/templates/variants/go-connectrpc/internal/app/service.go +202 -685
- package/templates/variants/go-connectrpc/internal/auth/middleware.go +289 -0
- package/templates/variants/go-connectrpc/internal/auth/middleware_test.go +38 -0
- package/templates/variants/go-connectrpc/internal/config/config.go +27 -11
- package/templates/variants/go-connectrpc/internal/connectapi/handler.go +78 -201
- package/templates/variants/go-connectrpc/internal/connectapi/waitlist_integration_test.go +122 -0
- package/templates/variants/go-connectrpc/internal/httpapi/routes.go +147 -9
- package/templates/variants/go-connectrpc/internal/temporal/activities.go +27 -0
- package/templates/variants/go-connectrpc/internal/temporal/worker.go +42 -0
- package/templates/variants/go-connectrpc/internal/temporal/workflows.go +18 -0
- package/templates/variants/go-connectrpc/migrations/0000_init.sql +12 -55
- package/templates/variants/go-connectrpc/migrations/atlas.sum +2 -0
- package/templates/variants/go-connectrpc/package.json +7 -1
- package/templates/variants/go-connectrpc/protos/waitlist/v1/waitlist.proto +93 -0
- package/templates/root/.github/workflows/buf-publish.yml +0 -19
- package/templates/root/.github/workflows/ci.yml +0 -26
- package/templates/root/.github/workflows/deploy.yml +0 -22
- package/templates/root/Dockerfile +0 -23
- package/templates/root/README.md +0 -69
- package/templates/root/buf.gen.yaml +0 -10
- package/templates/root/buf.yaml +0 -9
- package/templates/root/cmd/server/main.go +0 -44
- package/templates/root/gen/dns/v1/dns.pb.go +0 -623
- package/templates/root/gen/dns/v1/dnsv1connect/dns.connect.go +0 -192
- package/templates/root/go.mod +0 -10
- package/templates/root/internal/app/service.go +0 -152
- package/templates/root/internal/app/token_source.go +0 -50
- package/templates/root/internal/cloudflare/client.go +0 -160
- package/templates/root/internal/config/config.go +0 -55
- package/templates/root/internal/connectapi/handler.go +0 -79
- package/templates/root/internal/httpapi/routes.go +0 -93
- package/templates/root/internal/vault/client.go +0 -148
- package/templates/root/package.json +0 -12
- package/templates/root/protos/dns/v1/dns.proto +0 -58
- package/templates/root/scripts/cloudrun/bootstrap.ts +0 -65
- package/templates/root/scripts/cloudrun/config.ts +0 -50
- package/templates/root/scripts/cloudrun/deploy.ts +0 -41
- package/templates/root/scripts/cloudrun/lib.ts +0 -244
- package/templates/root/service.yaml +0 -50
- package/templates/root/test/go.test.ts +0 -19
- package/templates/shared/scripts/cloudrun/integrations.ts +0 -111
- package/templates/variants/bun-connectrpc/gen/protos/chat/v1/chat_pb.ts +0 -1078
- package/templates/variants/bun-connectrpc/protos/chat/v1/chat.proto +0 -228
- package/templates/variants/bun-connectrpc/src/chat/service.ts +0 -384
- package/templates/variants/bun-connectrpc/src/chat/types.ts +0 -142
- package/templates/variants/bun-connectrpc/src/storage.ts +0 -72
- package/templates/variants/bun-connectrpc/src/webhooks.ts +0 -35
- package/templates/variants/bun-connectrpc/test/list-messages.integration.test.ts +0 -182
- package/templates/variants/bun-hono/src/chat/service.ts +0 -384
- package/templates/variants/bun-hono/src/chat/types.ts +0 -142
- package/templates/variants/bun-hono/src/storage.ts +0 -72
- package/templates/variants/bun-hono/src/webhooks.ts +0 -35
- package/templates/variants/bun-hono/test/list-messages.integration.test.ts +0 -256
- package/templates/variants/go-chi/buf.gen.yaml +0 -12
- package/templates/variants/go-chi/buf.yaml +0 -9
- package/templates/variants/go-chi/cmd/migrate/main.go +0 -101
- package/templates/variants/go-chi/internal/httpapi/list_messages_integration_test.go +0 -298
- package/templates/variants/go-chi/protos/chat/v1/chat.proto +0 -219
- package/templates/variants/go-connectrpc/cmd/migrate/main.go +0 -101
- package/templates/variants/go-connectrpc/gen/chat/v1/chat.pb.go +0 -2512
- package/templates/variants/go-connectrpc/gen/chat/v1/chatv1connect/chat.connect.go +0 -571
- package/templates/variants/go-connectrpc/internal/connectapi/list_messages_integration_test.go +0 -216
- package/templates/variants/go-connectrpc/protos/chat/v1/chat.proto +0 -232
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
package httpapi
|
|
2
|
-
|
|
3
|
-
import (
|
|
4
|
-
"encoding/json"
|
|
5
|
-
"errors"
|
|
6
|
-
"net/http"
|
|
7
|
-
"strconv"
|
|
8
|
-
"strings"
|
|
9
|
-
|
|
10
|
-
"github.com/go-chi/chi/v5"
|
|
11
|
-
|
|
12
|
-
"{{MODULE_PATH}}/internal/app"
|
|
13
|
-
)
|
|
14
|
-
|
|
15
|
-
func RegisterRoutes(router chi.Router, service *app.DNSService) {
|
|
16
|
-
router.Get("/healthz", func(w http.ResponseWriter, _ *http.Request) {
|
|
17
|
-
writeJSON(w, http.StatusOK, map[string]string{"status": "ok"})
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
router.Route("/v1/dns/records", func(r chi.Router) {
|
|
21
|
-
r.Get("/", func(w http.ResponseWriter, request *http.Request) {
|
|
22
|
-
records, err := service.ListRecords(request.Context())
|
|
23
|
-
if err != nil {
|
|
24
|
-
writeError(w, err)
|
|
25
|
-
return
|
|
26
|
-
}
|
|
27
|
-
writeJSON(w, http.StatusOK, map[string]any{"records": records})
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
r.Post("/", func(w http.ResponseWriter, request *http.Request) {
|
|
31
|
-
var input app.CreateRecordInput
|
|
32
|
-
if err := decodeJSON(request, &input); err != nil {
|
|
33
|
-
writeError(w, err)
|
|
34
|
-
return
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
record, err := service.CreateRecord(request.Context(), input)
|
|
38
|
-
if err != nil {
|
|
39
|
-
writeError(w, err)
|
|
40
|
-
return
|
|
41
|
-
}
|
|
42
|
-
writeJSON(w, http.StatusCreated, map[string]any{"record": record})
|
|
43
|
-
})
|
|
44
|
-
|
|
45
|
-
r.Route("/{recordID}", func(r chi.Router) {
|
|
46
|
-
r.Put("/", func(w http.ResponseWriter, request *http.Request) {
|
|
47
|
-
var input app.UpdateRecordInput
|
|
48
|
-
if err := decodeJSON(request, &input); err != nil {
|
|
49
|
-
writeError(w, err)
|
|
50
|
-
return
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
record, err := service.UpdateRecord(request.Context(), chi.URLParam(request, "recordID"), input)
|
|
54
|
-
if err != nil {
|
|
55
|
-
writeError(w, err)
|
|
56
|
-
return
|
|
57
|
-
}
|
|
58
|
-
writeJSON(w, http.StatusOK, map[string]any{"record": record})
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
r.Delete("/", func(w http.ResponseWriter, request *http.Request) {
|
|
62
|
-
if err := service.DeleteRecord(request.Context(), chi.URLParam(request, "recordID")); err != nil {
|
|
63
|
-
writeError(w, err)
|
|
64
|
-
return
|
|
65
|
-
}
|
|
66
|
-
w.WriteHeader(http.StatusNoContent)
|
|
67
|
-
})
|
|
68
|
-
})
|
|
69
|
-
})
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
func decodeJSON(request *http.Request, out any) error {
|
|
73
|
-
defer request.Body.Close()
|
|
74
|
-
|
|
75
|
-
if err := json.NewDecoder(request.Body).Decode(out); err != nil {
|
|
76
|
-
return err
|
|
77
|
-
}
|
|
78
|
-
return nil
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
func writeJSON(w http.ResponseWriter, status int, payload any) {
|
|
82
|
-
w.Header().Set("Content-Type", "application/json")
|
|
83
|
-
w.WriteHeader(status)
|
|
84
|
-
_ = json.NewEncoder(w).Encode(payload)
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
func writeError(w http.ResponseWriter, err error) {
|
|
88
|
-
status := http.StatusInternalServerError
|
|
89
|
-
if errors.Is(err, strconv.ErrSyntax) || strings.Contains(strings.ToLower(err.Error()), "json") {
|
|
90
|
-
status = http.StatusBadRequest
|
|
91
|
-
}
|
|
92
|
-
writeJSON(w, status, map[string]string{"error": err.Error()})
|
|
93
|
-
}
|
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
package vault
|
|
2
|
-
|
|
3
|
-
import (
|
|
4
|
-
"bytes"
|
|
5
|
-
"context"
|
|
6
|
-
"encoding/json"
|
|
7
|
-
"fmt"
|
|
8
|
-
"io"
|
|
9
|
-
"net/http"
|
|
10
|
-
"os"
|
|
11
|
-
"strings"
|
|
12
|
-
"sync"
|
|
13
|
-
)
|
|
14
|
-
|
|
15
|
-
type AppRoleClient struct {
|
|
16
|
-
addr string
|
|
17
|
-
roleIDFile string
|
|
18
|
-
secretIDFile string
|
|
19
|
-
client *http.Client
|
|
20
|
-
|
|
21
|
-
mu sync.Mutex
|
|
22
|
-
token string
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
func NewAppRoleClient(addr string, roleIDFile string, secretIDFile string, client *http.Client) *AppRoleClient {
|
|
26
|
-
return &AppRoleClient{
|
|
27
|
-
addr: strings.TrimRight(addr, "/"),
|
|
28
|
-
roleIDFile: roleIDFile,
|
|
29
|
-
secretIDFile: secretIDFile,
|
|
30
|
-
client: client,
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
func (c *AppRoleClient) Get(ctx context.Context, path string, key string) (string, error) {
|
|
35
|
-
token, err := c.login(ctx)
|
|
36
|
-
if err != nil {
|
|
37
|
-
return "", err
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
request, err := http.NewRequestWithContext(ctx, http.MethodGet, fmt.Sprintf("%s/v1/secret/data/%s", c.addr, strings.TrimLeft(path, "/")), nil)
|
|
41
|
-
if err != nil {
|
|
42
|
-
return "", err
|
|
43
|
-
}
|
|
44
|
-
request.Header.Set("X-Vault-Token", token)
|
|
45
|
-
|
|
46
|
-
response, err := c.client.Do(request)
|
|
47
|
-
if err != nil {
|
|
48
|
-
return "", err
|
|
49
|
-
}
|
|
50
|
-
defer response.Body.Close()
|
|
51
|
-
|
|
52
|
-
raw, err := io.ReadAll(response.Body)
|
|
53
|
-
if err != nil {
|
|
54
|
-
return "", err
|
|
55
|
-
}
|
|
56
|
-
if response.StatusCode < 200 || response.StatusCode >= 300 {
|
|
57
|
-
return "", fmt.Errorf("vault read failed: status=%d body=%s", response.StatusCode, strings.TrimSpace(string(raw)))
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
var payload struct {
|
|
61
|
-
Data struct {
|
|
62
|
-
Data map[string]string `json:"data"`
|
|
63
|
-
} `json:"data"`
|
|
64
|
-
}
|
|
65
|
-
if err := json.Unmarshal(raw, &payload); err != nil {
|
|
66
|
-
return "", err
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
value := strings.TrimSpace(payload.Data.Data[key])
|
|
70
|
-
if value == "" {
|
|
71
|
-
return "", fmt.Errorf("vault secret key %q is empty", key)
|
|
72
|
-
}
|
|
73
|
-
return value, nil
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
func (c *AppRoleClient) login(ctx context.Context) (string, error) {
|
|
77
|
-
c.mu.Lock()
|
|
78
|
-
defer c.mu.Unlock()
|
|
79
|
-
|
|
80
|
-
if c.token != "" {
|
|
81
|
-
return c.token, nil
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
roleID, err := readSecretFile(c.roleIDFile)
|
|
85
|
-
if err != nil {
|
|
86
|
-
return "", err
|
|
87
|
-
}
|
|
88
|
-
secretID, err := readSecretFile(c.secretIDFile)
|
|
89
|
-
if err != nil {
|
|
90
|
-
return "", err
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
body, err := json.Marshal(map[string]string{
|
|
94
|
-
"role_id": roleID,
|
|
95
|
-
"secret_id": secretID,
|
|
96
|
-
})
|
|
97
|
-
if err != nil {
|
|
98
|
-
return "", err
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
request, err := http.NewRequestWithContext(ctx, http.MethodPost, c.addr+"/v1/auth/approle/login", bytes.NewReader(body))
|
|
102
|
-
if err != nil {
|
|
103
|
-
return "", err
|
|
104
|
-
}
|
|
105
|
-
request.Header.Set("Content-Type", "application/json")
|
|
106
|
-
|
|
107
|
-
response, err := c.client.Do(request)
|
|
108
|
-
if err != nil {
|
|
109
|
-
return "", err
|
|
110
|
-
}
|
|
111
|
-
defer response.Body.Close()
|
|
112
|
-
|
|
113
|
-
raw, err := io.ReadAll(response.Body)
|
|
114
|
-
if err != nil {
|
|
115
|
-
return "", err
|
|
116
|
-
}
|
|
117
|
-
if response.StatusCode < 200 || response.StatusCode >= 300 {
|
|
118
|
-
return "", fmt.Errorf("vault login failed: status=%d body=%s", response.StatusCode, strings.TrimSpace(string(raw)))
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
var payload struct {
|
|
122
|
-
Auth struct {
|
|
123
|
-
ClientToken string `json:"client_token"`
|
|
124
|
-
} `json:"auth"`
|
|
125
|
-
}
|
|
126
|
-
if err := json.Unmarshal(raw, &payload); err != nil {
|
|
127
|
-
return "", err
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
c.token = strings.TrimSpace(payload.Auth.ClientToken)
|
|
131
|
-
if c.token == "" {
|
|
132
|
-
return "", fmt.Errorf("vault returned an empty client token")
|
|
133
|
-
}
|
|
134
|
-
return c.token, nil
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
func readSecretFile(path string) (string, error) {
|
|
138
|
-
bytes, err := os.ReadFile(path)
|
|
139
|
-
if err != nil {
|
|
140
|
-
return "", err
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
value := strings.TrimSpace(string(bytes))
|
|
144
|
-
if value == "" {
|
|
145
|
-
return "", fmt.Errorf("secret file %q is empty", path)
|
|
146
|
-
}
|
|
147
|
-
return value, nil
|
|
148
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "{{SERVICE_NAME}}",
|
|
3
|
-
"private": true,
|
|
4
|
-
"type": "module",
|
|
5
|
-
"scripts": {
|
|
6
|
-
"dev": "go run ./cmd/server",
|
|
7
|
-
"gen": "buf generate",
|
|
8
|
-
"lint": "go vet ./... && buf lint",
|
|
9
|
-
"bootstrap": "bun run ./scripts/cloudrun/bootstrap.ts",
|
|
10
|
-
"deploy": "bun run ./scripts/cloudrun/deploy.ts"
|
|
11
|
-
}
|
|
12
|
-
}
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
syntax = "proto3";
|
|
2
|
-
|
|
3
|
-
package dns.v1;
|
|
4
|
-
|
|
5
|
-
option go_package = "{{MODULE_PATH}}/gen/dns/v1;dnsv1";
|
|
6
|
-
|
|
7
|
-
service DNSService {
|
|
8
|
-
rpc ListRecords(ListRecordsRequest) returns (ListRecordsResponse) {}
|
|
9
|
-
rpc CreateRecord(CreateRecordRequest) returns (CreateRecordResponse) {}
|
|
10
|
-
rpc UpdateRecord(UpdateRecordRequest) returns (UpdateRecordResponse) {}
|
|
11
|
-
rpc DeleteRecord(DeleteRecordRequest) returns (DeleteRecordResponse) {}
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
message Record {
|
|
15
|
-
string id = 1;
|
|
16
|
-
string type = 2;
|
|
17
|
-
string name = 3;
|
|
18
|
-
string content = 4;
|
|
19
|
-
int32 ttl = 5;
|
|
20
|
-
bool proxied = 6;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
message ListRecordsRequest {}
|
|
24
|
-
|
|
25
|
-
message ListRecordsResponse {
|
|
26
|
-
repeated Record records = 1;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
message CreateRecordRequest {
|
|
30
|
-
string type = 1;
|
|
31
|
-
string name = 2;
|
|
32
|
-
string content = 3;
|
|
33
|
-
int32 ttl = 4;
|
|
34
|
-
bool proxied = 5;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
message CreateRecordResponse {
|
|
38
|
-
Record record = 1;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
message UpdateRecordRequest {
|
|
42
|
-
string id = 1;
|
|
43
|
-
string type = 2;
|
|
44
|
-
string name = 3;
|
|
45
|
-
string content = 4;
|
|
46
|
-
int32 ttl = 5;
|
|
47
|
-
bool proxied = 6;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
message UpdateRecordResponse {
|
|
51
|
-
Record record = 1;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
message DeleteRecordRequest {
|
|
55
|
-
string id = 1;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
message DeleteRecordResponse {}
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import { bootstrapSecrets, config } from "./config";
|
|
2
|
-
import {
|
|
3
|
-
ensureProjectRole,
|
|
4
|
-
ensureSecret,
|
|
5
|
-
ensureSecretAccessor,
|
|
6
|
-
ensureServiceAccount,
|
|
7
|
-
ensureServiceAccountRole,
|
|
8
|
-
ensureWorkloadIdentityPool,
|
|
9
|
-
ensureWorkloadIdentityProvider,
|
|
10
|
-
gcloud,
|
|
11
|
-
requireCommand,
|
|
12
|
-
setGithubSecret,
|
|
13
|
-
setGithubVariable,
|
|
14
|
-
workloadIdentityPoolResource,
|
|
15
|
-
workloadIdentityProviderResource,
|
|
16
|
-
} from "./lib";
|
|
17
|
-
|
|
18
|
-
export async function bootstrap() {
|
|
19
|
-
requireCommand("gcloud");
|
|
20
|
-
requireCommand("gh");
|
|
21
|
-
|
|
22
|
-
gcloud(["services", "enable", ...config.requiredApis, "--project", config.projectId]);
|
|
23
|
-
|
|
24
|
-
ensureServiceAccount(config.runtimeServiceAccount);
|
|
25
|
-
ensureServiceAccount(config.deployerServiceAccount);
|
|
26
|
-
|
|
27
|
-
ensureProjectRole(`serviceAccount:${config.deployerServiceAccount}`, "roles/run.admin");
|
|
28
|
-
ensureProjectRole(`serviceAccount:${config.deployerServiceAccount}`, "roles/cloudbuild.builds.editor");
|
|
29
|
-
ensureProjectRole(`serviceAccount:${config.deployerServiceAccount}`, "roles/serviceusage.serviceUsageConsumer");
|
|
30
|
-
|
|
31
|
-
ensureServiceAccountRole(config.runtimeServiceAccount, `serviceAccount:${config.deployerServiceAccount}`, "roles/iam.serviceAccountUser");
|
|
32
|
-
|
|
33
|
-
for (const secret of bootstrapSecrets) {
|
|
34
|
-
ensureSecret(secret.secretName, secret.bootstrapEnv);
|
|
35
|
-
ensureSecretAccessor(secret.secretName, `serviceAccount:${config.runtimeServiceAccount}`);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
ensureWorkloadIdentityPool();
|
|
39
|
-
ensureWorkloadIdentityProvider();
|
|
40
|
-
|
|
41
|
-
ensureServiceAccountRole(
|
|
42
|
-
config.deployerServiceAccount,
|
|
43
|
-
`principalSet://iam.googleapis.com/${workloadIdentityPoolResource()}/attribute.repository/${config.githubRepo}`,
|
|
44
|
-
"roles/iam.workloadIdentityUser"
|
|
45
|
-
);
|
|
46
|
-
|
|
47
|
-
for (const [name, value] of Object.entries(config.githubVariables)) {
|
|
48
|
-
setGithubVariable(name, value);
|
|
49
|
-
}
|
|
50
|
-
setGithubVariable("GCP_WIF_PROVIDER", workloadIdentityProviderResource());
|
|
51
|
-
setGithubVariable("GCP_DEPLOYER_SERVICE_ACCOUNT", config.deployerServiceAccount);
|
|
52
|
-
|
|
53
|
-
if (config.bufModule) {
|
|
54
|
-
setGithubVariable("BUF_MODULE", config.bufModule);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const bufToken = process.env.BUF_TOKEN?.trim();
|
|
58
|
-
if (bufToken && config.bufModule) {
|
|
59
|
-
setGithubSecret("BUF_TOKEN", bufToken);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
if (import.meta.main) {
|
|
64
|
-
await bootstrap();
|
|
65
|
-
}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
export const config = {
|
|
2
|
-
serviceName: "{{SERVICE_NAME}}",
|
|
3
|
-
projectId: "{{PROJECT_ID}}",
|
|
4
|
-
region: "{{REGION}}",
|
|
5
|
-
githubRepo: "{{GITHUB_REPO}}",
|
|
6
|
-
bufModule: "{{BUF_MODULE}}",
|
|
7
|
-
artifactRepository: "cloud-run",
|
|
8
|
-
runtimeServiceAccount: "{{RUNTIME_SERVICE_ACCOUNT}}",
|
|
9
|
-
deployerServiceAccount: "{{DEPLOYER_SERVICE_ACCOUNT}}",
|
|
10
|
-
vaultRoleIdSecret: "{{VAULT_ROLE_ID_SECRET}}",
|
|
11
|
-
vaultSecretIdSecret: "{{VAULT_SECRET_ID_SECRET}}",
|
|
12
|
-
workloadIdentityPoolId: "{{WIF_POOL_ID}}",
|
|
13
|
-
workloadIdentityProviderId: "{{WIF_PROVIDER_ID}}",
|
|
14
|
-
requiredApis: [
|
|
15
|
-
"run.googleapis.com",
|
|
16
|
-
"cloudbuild.googleapis.com",
|
|
17
|
-
"artifactregistry.googleapis.com",
|
|
18
|
-
"iamcredentials.googleapis.com",
|
|
19
|
-
"sts.googleapis.com",
|
|
20
|
-
"secretmanager.googleapis.com",
|
|
21
|
-
"serviceusage.googleapis.com",
|
|
22
|
-
],
|
|
23
|
-
githubVariables: {
|
|
24
|
-
GCP_PROJECT_ID: "{{PROJECT_ID}}",
|
|
25
|
-
GCP_REGION: "{{REGION}}",
|
|
26
|
-
CLOUD_RUN_SERVICE: "{{SERVICE_NAME}}",
|
|
27
|
-
},
|
|
28
|
-
} as const;
|
|
29
|
-
|
|
30
|
-
export const manifestEnv = {
|
|
31
|
-
SERVICE_NAME: "{{SERVICE_NAME}}",
|
|
32
|
-
RUNTIME_SERVICE_ACCOUNT: "{{RUNTIME_SERVICE_ACCOUNT}}",
|
|
33
|
-
VAULT_ADDR: "{{VAULT_ADDR}}",
|
|
34
|
-
VAULT_SECRET_PATH: "{{VAULT_SECRET_PATH}}",
|
|
35
|
-
VAULT_SECRET_KEY: "{{VAULT_SECRET_KEY}}",
|
|
36
|
-
CLOUDFLARE_ZONE_ID: "{{CLOUDFLARE_ZONE_ID}}",
|
|
37
|
-
VAULT_ROLE_ID_SECRET: "{{VAULT_ROLE_ID_SECRET}}",
|
|
38
|
-
VAULT_SECRET_ID_SECRET: "{{VAULT_SECRET_ID_SECRET}}",
|
|
39
|
-
} as const;
|
|
40
|
-
|
|
41
|
-
export const bootstrapSecrets = [
|
|
42
|
-
{
|
|
43
|
-
secretName: "{{VAULT_ROLE_ID_SECRET}}",
|
|
44
|
-
bootstrapEnv: "BOOTSTRAP_VAULT_ROLE_ID",
|
|
45
|
-
},
|
|
46
|
-
{
|
|
47
|
-
secretName: "{{VAULT_SECRET_ID_SECRET}}",
|
|
48
|
-
bootstrapEnv: "BOOTSTRAP_VAULT_SECRET_ID",
|
|
49
|
-
},
|
|
50
|
-
] as const;
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { bootstrap } from "./bootstrap";
|
|
2
|
-
import { config } from "./config";
|
|
3
|
-
import { ensureArtifactRepository, gcloud, imageUrl, requireCommand, serviceUrl, writeRenderedManifest } from "./lib";
|
|
4
|
-
|
|
5
|
-
export async function deploy(args = Bun.argv.slice(2)) {
|
|
6
|
-
requireCommand("gcloud");
|
|
7
|
-
requireCommand("bun");
|
|
8
|
-
|
|
9
|
-
const ci = args.includes("--ci");
|
|
10
|
-
if (!ci) {
|
|
11
|
-
await bootstrap();
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
ensureArtifactRepository();
|
|
15
|
-
|
|
16
|
-
const image = imageUrl();
|
|
17
|
-
gcloud(["builds", "submit", "--project", config.projectId, "--region", config.region, "--tag", image]);
|
|
18
|
-
|
|
19
|
-
const renderedManifestPath = await writeRenderedManifest(image);
|
|
20
|
-
gcloud(["run", "services", "replace", renderedManifestPath.pathname, "--project", config.projectId, "--region", config.region]);
|
|
21
|
-
gcloud([
|
|
22
|
-
"run",
|
|
23
|
-
"services",
|
|
24
|
-
"add-iam-policy-binding",
|
|
25
|
-
config.serviceName,
|
|
26
|
-
"--project",
|
|
27
|
-
config.projectId,
|
|
28
|
-
"--region",
|
|
29
|
-
config.region,
|
|
30
|
-
"--member",
|
|
31
|
-
"allUsers",
|
|
32
|
-
"--role",
|
|
33
|
-
"roles/run.invoker",
|
|
34
|
-
]);
|
|
35
|
-
|
|
36
|
-
console.log(serviceUrl());
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
if (import.meta.main) {
|
|
40
|
-
await deploy();
|
|
41
|
-
}
|