Skip to content

Commit d2348ef

Browse files
committed
v0.0.1: local dev trust store bootstrap
1 parent 701eb2f commit d2348ef

File tree

17 files changed

+402
-120
lines changed

17 files changed

+402
-120
lines changed

api/api.go

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,14 @@ package api
44

55
import (
66
"errors"
7+
"fmt"
8+
"mime"
79
"net/http"
810
"net/url"
911

1012
"github.com/anchordotdev/cli"
1113
"github.com/anchordotdev/cli/keyring"
14+
"golang.org/x/exp/slices"
1215
)
1316

1417
var (
@@ -19,18 +22,25 @@ var (
1922
func Client(cfg *cli.Config) (*http.Client, error) {
2023
client := &http.Client{
2124
Transport: urlRewriter{
22-
RoundTripper: new(http.Transport),
23-
URL: cfg.API.URL,
25+
RoundTripper: responseChecker{
26+
RoundTripper: new(http.Transport),
27+
},
28+
URL: cfg.API.URL,
2429
},
2530
}
2631

2732
apiToken := cfg.API.Token
2833
if apiToken == "" {
29-
var err error
30-
if apiToken, err = keyring.Get(cfg, keyring.APIToken); err == keyring.ErrNotFound {
34+
var (
35+
kr = keyring.Keyring{Config: cfg}
36+
37+
err error
38+
)
39+
40+
if apiToken, err = kr.Get(keyring.APIToken); err == keyring.ErrNotFound {
3141
return client, ErrSignedOut
3242
} else if err != nil {
33-
return nil, err
43+
return nil, fmt.Errorf("reading API token from keyring failed: %w", err)
3444
}
3545
}
3646

@@ -56,6 +66,30 @@ func (r basicAuther) RoundTrip(req *http.Request) (*http.Response, error) {
5666
return r.RoundTripper.RoundTrip(req)
5767
}
5868

69+
type responseChecker struct {
70+
http.RoundTripper
71+
}
72+
73+
var jsonMediaTypes = mediaTypes{
74+
"application/json",
75+
"application/problem+json",
76+
}
77+
78+
func (r responseChecker) RoundTrip(req *http.Request) (*http.Response, error) {
79+
res, err := r.RoundTripper.RoundTrip(req)
80+
if err != nil {
81+
return nil, fmt.Errorf("request error %s %s: %w", req.Method, req.URL.Path, err)
82+
}
83+
84+
if res.StatusCode == 500 {
85+
return nil, fmt.Errorf("request failed: %w", err)
86+
}
87+
if contentType := res.Header.Get("Content-Type"); !jsonMediaTypes.Matches(contentType) {
88+
return nil, fmt.Errorf("non-json response received: %q: %w", contentType, err)
89+
}
90+
return res, nil
91+
}
92+
5993
type urlRewriter struct {
6094
http.RoundTripper
6195

@@ -67,10 +101,17 @@ func (r urlRewriter) RoundTrip(req *http.Request) (*http.Response, error) {
67101
if err != nil {
68102
return nil, err
69103
}
70-
if u, err = u.Parse(req.URL.Path); err != nil {
71-
return nil, err
72-
}
73-
req.URL = u
104+
req.URL = u.JoinPath(req.URL.Path)
74105

75106
return r.RoundTripper.RoundTrip(req)
76107
}
108+
109+
type mediaTypes []string
110+
111+
func (s mediaTypes) Matches(val string) bool {
112+
media, _, err := mime.ParseMediaType(val)
113+
if err != nil {
114+
return false
115+
}
116+
return slices.Contains(s, media)
117+
}

api/apitest/apitest.go

Lines changed: 57 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"errors"
77
"flag"
88
"path/filepath"
9+
"strings"
910

1011
"io"
1112
"log"
@@ -32,6 +33,7 @@ var (
3233
)
3334

3435
type Server struct {
36+
Host string
3537
RootDir string
3638

3739
URL string
@@ -48,6 +50,26 @@ func (s *Server) Close() {
4850
s.waitfn()
4951
}
5052

53+
func (s *Server) IsProxy() bool {
54+
return *proxy
55+
}
56+
57+
func (s *Server) GeneratePAT(email string) (string, error) {
58+
if !s.IsProxy() {
59+
return "test-token", nil
60+
}
61+
62+
cmd := exec.Command("script/clitest-gen-pat", email)
63+
cmd.Dir = s.RootDir
64+
65+
out, err := cmd.Output()
66+
if err != nil {
67+
return "", err
68+
}
69+
70+
return strings.TrimSpace(string(out)), nil
71+
}
72+
5173
func (s *Server) Start(ctx context.Context) error {
5274
if *proxy {
5375
return s.StartProxy(ctx)
@@ -69,7 +91,17 @@ func (s *Server) StartMock(ctx context.Context) error {
6991
return err
7092
}
7193

72-
s.URL = "http://" + addr + "/"
94+
host, port, err := net.SplitHostPort(addr)
95+
if err != nil {
96+
stopfn()
97+
return err
98+
}
99+
100+
if s.Host != "" {
101+
host = s.Host
102+
}
103+
104+
s.URL = "http://" + host + ":" + port + "/v0"
73105
s.stopfn = stopfn
74106
s.waitfn = func() { waitfn() }
75107

@@ -92,7 +124,17 @@ func (s *Server) StartProxy(ctx context.Context) error {
92124
return err
93125
}
94126

95-
addr, waitPrism, err := s.startProxy(ctx, addrRails)
127+
host, port, err := net.SplitHostPort(addrRails)
128+
if err != nil {
129+
stopfn()
130+
return err
131+
}
132+
133+
if s.Host != "" {
134+
host = s.Host
135+
}
136+
137+
addr, waitPrism, err := s.startProxy(ctx, host+":"+port)
96138
if err != nil {
97139
lock.Unlock()
98140
stopfn()
@@ -115,7 +157,17 @@ func (s *Server) StartProxy(ctx context.Context) error {
115157
group.Go(waitPrism)
116158
group.Go(waitRails)
117159

118-
s.URL = "http://" + addr + "/"
160+
host, port, err = net.SplitHostPort(addr)
161+
if err != nil {
162+
stopfn()
163+
return err
164+
}
165+
166+
if s.Host != "" {
167+
host = s.Host
168+
}
169+
170+
s.URL = "http://" + host + ":" + port + "/v0"
119171
s.stopfn = stopfn
120172
s.waitfn = func() {
121173
defer lock.Unlock()
@@ -178,13 +230,13 @@ func (s *Server) startRails(ctx context.Context) (string, func() error, error) {
178230
return "", nil, err
179231
}
180232

181-
host, port, err := net.SplitHostPort(addr)
233+
_, port, err := net.SplitHostPort(addr)
182234
if err != nil {
183235
return "", nil, err
184236
}
185237

186238
args := []string{
187-
"rails", "server", "--port", port, "--binding", host,
239+
"script/clitest-server", "::", port,
188240
}
189241

190242
wait, err := s.startCmd(ctx, args)

api/openapi.gen.go

Lines changed: 43 additions & 35 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

auth/auth_test.go

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,10 @@ import (
88
"github.com/anchordotdev/cli/api/apitest"
99
)
1010

11-
var (
12-
srv = &apitest.Server{
13-
RootDir: "../..",
14-
// RootDir: "../..",
15-
}
16-
17-
proxyMode = flag.Bool("proxy", false, "run prism in proxy mode")
18-
)
11+
var srv = &apitest.Server{
12+
Host: "api.anchor.lcl.host",
13+
RootDir: "../..",
14+
}
1915

2016
func TestMain(m *testing.M) {
2117
flag.Parse()

0 commit comments

Comments
 (0)