porting all github actions from bluesky-social/indigo to tangled CI

initial tests

+51
atproto/client/admin_auth_test.go
··· 1 + package client 2 + 3 + import ( 4 + "context" 5 + "fmt" 6 + "net/http" 7 + "net/http/httptest" 8 + "testing" 9 + 10 + "github.com/bluesky-social/indigo/atproto/syntax" 11 + 12 + "github.com/stretchr/testify/assert" 13 + ) 14 + 15 + func adminHandler(w http.ResponseWriter, r *http.Request) { 16 + username, password, ok := r.BasicAuth() 17 + if ok && username == "admin" && password == "secret" { 18 + w.Header().Set("Content-Type", "application/json") 19 + fmt.Fprintln(w, "{\"status\":\"success\"}") 20 + return 21 + } 22 + w.Header().Set("WWW-Authenticate", `Basic realm="admin", charset="UTF-8"`) 23 + http.Error(w, "Unauthorized", http.StatusUnauthorized) 24 + } 25 + 26 + func TestAdminAuth(t *testing.T) { 27 + assert := assert.New(t) 28 + ctx := context.Background() 29 + var apierr *APIError 30 + 31 + srv := httptest.NewServer(http.HandlerFunc(adminHandler)) 32 + defer srv.Close() 33 + 34 + { 35 + c := NewPublicClient(srv.URL) 36 + err := c.Get(ctx, syntax.NSID("com.example.get"), nil, nil) 37 + assert.ErrorAs(err, &apierr) 38 + } 39 + 40 + { 41 + c := NewAdminClient(srv.URL, "wrong") 42 + err := c.Get(ctx, syntax.NSID("com.example.get"), nil, nil) 43 + assert.ErrorAs(err, &apierr) 44 + } 45 + 46 + { 47 + c := NewAdminClient(srv.URL, "secret") 48 + err := c.Get(ctx, syntax.NSID("com.example.get"), nil, nil) 49 + assert.NoError(err) 50 + } 51 + }
+2 -2
atproto/client/examples_test.go
··· 17 17 } 18 18 19 19 endpoint := syntax.NSID("app.bsky.actor.getProfile") 20 - params := map[string]string{ 21 - "actor": "atproto.com", 20 + params := map[string][]string{ 21 + "actor": []string{"atproto.com"}, 22 22 } 23 23 var profile appbsky.ActorDefs_ProfileViewDetailed 24 24 if err := c.Get(ctx, endpoint, params, &profile); err != nil {
+127
atproto/client/password_auth_test.go
··· 1 + package client 2 + 3 + import ( 4 + "context" 5 + "encoding/json" 6 + "fmt" 7 + "net/http" 8 + "net/http/httptest" 9 + "strings" 10 + "testing" 11 + 12 + "github.com/bluesky-social/indigo/atproto/identity" 13 + "github.com/bluesky-social/indigo/atproto/syntax" 14 + 15 + "github.com/stretchr/testify/assert" 16 + "github.com/stretchr/testify/require" 17 + ) 18 + 19 + func pwHandler(w http.ResponseWriter, r *http.Request) { 20 + switch r.URL.Path { 21 + case "/xrpc/com.atproto.server.refreshSession": 22 + //fmt.Println("refreshSession handler...") 23 + hdr := r.Header.Get("Authorization") 24 + if hdr != "Bearer refresh1" { 25 + fmt.Printf("refreshSession header: %s\n", hdr) 26 + w.Header().Set("WWW-Authenticate", `Bearer`) 27 + http.Error(w, "Unauthorized", http.StatusUnauthorized) 28 + return 29 + } 30 + w.Header().Set("Content-Type", "application/json") 31 + json.NewEncoder(w).Encode(map[string]string{ 32 + "did": "did:web:account.example.com", 33 + "accessJwt": "access2", 34 + "refreshJwt": "refresh2", 35 + }) 36 + return 37 + case "/xrpc/com.atproto.server.createSession": 38 + if !strings.HasPrefix(r.Header.Get("Content-Type"), "application/json") { 39 + fmt.Println("createSession Content-Type") 40 + http.Error(w, "Bad Request", http.StatusBadRequest) 41 + return 42 + } 43 + var body map[string]string 44 + if err := json.NewDecoder(r.Body).Decode(&body); err != nil { 45 + fmt.Println("createSession JSON") 46 + http.Error(w, "Bad Request", http.StatusBadRequest) 47 + return 48 + } 49 + if body["identifier"] != "did:web:account.example.com" || body["password"] != "password1" { 50 + fmt.Println("createSession wrong password") 51 + http.Error(w, "Bad Request", http.StatusUnauthorized) 52 + return 53 + } 54 + 55 + w.Header().Set("Content-Type", "application/json") 56 + json.NewEncoder(w).Encode(map[string]string{ 57 + "did": body["identifier"], 58 + "accessJwt": "access1", 59 + "refreshJwt": "refresh1", 60 + }) 61 + return 62 + case "/xrpc/com.example.get": 63 + hdr := r.Header.Get("Authorization") 64 + if hdr == "Bearer access1" { 65 + w.Header().Set("Content-Type", "application/json") 66 + fmt.Fprintln(w, "{\"status\":\"success\"}") 67 + return 68 + } else { 69 + fmt.Printf("get header: %s\n", hdr) 70 + w.Header().Set("WWW-Authenticate", `Bearer`) 71 + http.Error(w, "Unauthorized", http.StatusUnauthorized) 72 + return 73 + } 74 + case "/xrpc/com.example.expire": 75 + hdr := r.Header.Get("Authorization") 76 + if hdr == "Bearer access1" { 77 + //fmt.Println("forcing refresh...") 78 + w.Header().Set("Content-Type", "application/json") 79 + w.WriteHeader(400) 80 + fmt.Fprintln(w, "{\"error\":\"ExpiredToken\"}") 81 + return 82 + } else if hdr == "Bearer access2" { 83 + w.Header().Set("Content-Type", "application/json") 84 + fmt.Fprintln(w, "{\"status\":\"success\"}") 85 + return 86 + } else { 87 + fmt.Printf("expire header: %s\n", hdr) 88 + w.Header().Set("WWW-Authenticate", `Bearer`) 89 + http.Error(w, "Unauthorized", http.StatusUnauthorized) 90 + return 91 + } 92 + default: 93 + http.NotFound(w, r) 94 + return 95 + } 96 + } 97 + 98 + func TestPasswordAuth(t *testing.T) { 99 + assert := assert.New(t) 100 + require := require.New(t) 101 + ctx := context.Background() 102 + //var apierr *APIError 103 + 104 + srv := httptest.NewServer(http.HandlerFunc(pwHandler)) 105 + defer srv.Close() 106 + 107 + dir := identity.NewMockDirectory() 108 + dir.Insert(identity.Identity{ 109 + DID: "did:web:account.example.com", 110 + Handle: "user1.example.com", 111 + Services: map[string]identity.Service{ 112 + "atproto_pds": { 113 + Type: "AtprotoPersonalDataServer", 114 + URL: srv.URL, 115 + }, 116 + }, 117 + }) 118 + 119 + { 120 + c, err := LoginWithPassword(ctx, &dir, syntax.Handle("user1.example.com").AtIdentifier(), "password1", "") 121 + require.NoError(err) 122 + err = c.Get(ctx, syntax.NSID("com.example.get"), nil, nil) 123 + assert.NoError(err) 124 + err = c.Get(ctx, syntax.NSID("com.example.expire"), nil, nil) 125 + assert.NoError(err) 126 + } 127 + }