forked from tangled.org/core
Monorepo for Tangled

appview: improve the logging situation a bit

needs a lot more work, but we now inject slog in several places.

Signed-off-by: oppiliappan <me@oppi.li>

authored by oppi.li and committed by oppi.li c9726979 3ebdcdbd

Changed files
+427 -234
appview
cmd
appview
spindle
jetstream
nix
xrpc
serviceauth
+36 -28
appview/db/db.go
··· 4 "context" 5 "database/sql" 6 "fmt" 7 - "log" 8 "reflect" 9 "strings" 10 11 _ "github.com/mattn/go-sqlite3" 12 ) 13 14 type DB struct { 15 *sql.DB 16 } 17 18 type Execer interface { ··· 26 PrepareContext(ctx context.Context, query string) (*sql.Stmt, error) 27 } 28 29 - func Make(dbPath string) (*DB, error) { 30 // https://github.com/mattn/go-sqlite3#connection-string 31 opts := []string{ 32 "_foreign_keys=1", ··· 35 "_auto_vacuum=incremental", 36 } 37 38 db, err := sql.Open("sqlite3", dbPath+"?"+strings.Join(opts, "&")) 39 if err != nil { 40 return nil, err 41 } 42 - 43 - ctx := context.Background() 44 45 conn, err := db.Conn(ctx) 46 if err != nil { ··· 574 } 575 576 // run migrations 577 - runMigration(conn, "add-description-to-repos", func(tx *sql.Tx) error { 578 tx.Exec(` 579 alter table repos add column description text check (length(description) <= 200); 580 `) 581 return nil 582 }) 583 584 - runMigration(conn, "add-rkey-to-pubkeys", func(tx *sql.Tx) error { 585 // add unconstrained column 586 _, err := tx.Exec(` 587 alter table public_keys ··· 604 return nil 605 }) 606 607 - runMigration(conn, "add-rkey-to-comments", func(tx *sql.Tx) error { 608 _, err := tx.Exec(` 609 alter table comments drop column comment_at; 610 alter table comments add column rkey text; ··· 612 return err 613 }) 614 615 - runMigration(conn, "add-deleted-and-edited-to-issue-comments", func(tx *sql.Tx) error { 616 _, err := tx.Exec(` 617 alter table comments add column deleted text; -- timestamp 618 alter table comments add column edited text; -- timestamp ··· 620 return err 621 }) 622 623 - runMigration(conn, "add-source-info-to-pulls-and-submissions", func(tx *sql.Tx) error { 624 _, err := tx.Exec(` 625 alter table pulls add column source_branch text; 626 alter table pulls add column source_repo_at text; ··· 629 return err 630 }) 631 632 - runMigration(conn, "add-source-to-repos", func(tx *sql.Tx) error { 633 _, err := tx.Exec(` 634 alter table repos add column source text; 635 `) ··· 641 // 642 // [0]: https://sqlite.org/pragma.html#pragma_foreign_keys 643 conn.ExecContext(ctx, "pragma foreign_keys = off;") 644 - runMigration(conn, "recreate-pulls-column-for-stacking-support", func(tx *sql.Tx) error { 645 _, err := tx.Exec(` 646 create table pulls_new ( 647 -- identifiers ··· 698 }) 699 conn.ExecContext(ctx, "pragma foreign_keys = on;") 700 701 - runMigration(conn, "add-spindle-to-repos", func(tx *sql.Tx) error { 702 tx.Exec(` 703 alter table repos add column spindle text; 704 `) ··· 708 // drop all knot secrets, add unique constraint to knots 709 // 710 // knots will henceforth use service auth for signed requests 711 - runMigration(conn, "no-more-secrets", func(tx *sql.Tx) error { 712 _, err := tx.Exec(` 713 create table registrations_new ( 714 id integer primary key autoincrement, ··· 731 }) 732 733 // recreate and add rkey + created columns with default constraint 734 - runMigration(conn, "rework-collaborators-table", func(tx *sql.Tx) error { 735 // create new table 736 // - repo_at instead of repo integer 737 // - rkey field ··· 785 return err 786 }) 787 788 - runMigration(conn, "add-rkey-to-issues", func(tx *sql.Tx) error { 789 _, err := tx.Exec(` 790 alter table issues add column rkey text not null default ''; 791 ··· 797 }) 798 799 // repurpose the read-only column to "needs-upgrade" 800 - runMigration(conn, "rename-registrations-read-only-to-needs-upgrade", func(tx *sql.Tx) error { 801 _, err := tx.Exec(` 802 alter table registrations rename column read_only to needs_upgrade; 803 `) ··· 805 }) 806 807 // require all knots to upgrade after the release of total xrpc 808 - runMigration(conn, "migrate-knots-to-total-xrpc", func(tx *sql.Tx) error { 809 _, err := tx.Exec(` 810 update registrations set needs_upgrade = 1; 811 `) ··· 813 }) 814 815 // require all knots to upgrade after the release of total xrpc 816 - runMigration(conn, "migrate-spindles-to-xrpc-owner", func(tx *sql.Tx) error { 817 _, err := tx.Exec(` 818 alter table spindles add column needs_upgrade integer not null default 0; 819 `) ··· 831 // 832 // disable foreign-keys for the next migration 833 conn.ExecContext(ctx, "pragma foreign_keys = off;") 834 - runMigration(conn, "remove-issue-at-from-issues", func(tx *sql.Tx) error { 835 _, err := tx.Exec(` 836 create table if not exists issues_new ( 837 -- identifiers ··· 901 // - new columns 902 // * column "reply_to" which can be any other comment 903 // * column "at-uri" which is a generated column 904 - runMigration(conn, "rework-issue-comments", func(tx *sql.Tx) error { 905 _, err := tx.Exec(` 906 create table if not exists issue_comments ( 907 -- identifiers ··· 961 // 962 // disable foreign-keys for the next migration 963 conn.ExecContext(ctx, "pragma foreign_keys = off;") 964 - runMigration(conn, "add-at-uri-to-pulls", func(tx *sql.Tx) error { 965 _, err := tx.Exec(` 966 create table if not exists pulls_new ( 967 -- identifiers ··· 1042 // 1043 // disable foreign-keys for the next migration 1044 conn.ExecContext(ctx, "pragma foreign_keys = off;") 1045 - runMigration(conn, "remove-repo-at-pull-id-from-pull-submissions", func(tx *sql.Tx) error { 1046 _, err := tx.Exec(` 1047 create table if not exists pull_submissions_new ( 1048 -- identifiers ··· 1094 }) 1095 conn.ExecContext(ctx, "pragma foreign_keys = on;") 1096 1097 - return &DB{db}, nil 1098 } 1099 1100 type migrationFn = func(*sql.Tx) error 1101 1102 - func runMigration(c *sql.Conn, name string, migrationFn migrationFn) error { 1103 tx, err := c.BeginTx(context.Background(), nil) 1104 if err != nil { 1105 return err ··· 1116 // run migration 1117 err = migrationFn(tx) 1118 if err != nil { 1119 - log.Printf("Failed to run migration %s: %v", name, err) 1120 return err 1121 } 1122 1123 // mark migration as complete 1124 _, err = tx.Exec("insert into migrations (name) values (?)", name) 1125 if err != nil { 1126 - log.Printf("Failed to mark migration %s as complete: %v", name, err) 1127 return err 1128 } 1129 ··· 1132 return err 1133 } 1134 1135 - log.Printf("migration %s applied successfully", name) 1136 } else { 1137 - log.Printf("skipped migration %s, already applied", name) 1138 } 1139 1140 return nil
··· 4 "context" 5 "database/sql" 6 "fmt" 7 + "log/slog" 8 "reflect" 9 "strings" 10 11 _ "github.com/mattn/go-sqlite3" 12 + "tangled.org/core/log" 13 ) 14 15 type DB struct { 16 *sql.DB 17 + logger *slog.Logger 18 } 19 20 type Execer interface { ··· 28 PrepareContext(ctx context.Context, query string) (*sql.Stmt, error) 29 } 30 31 + func Make(ctx context.Context, dbPath string) (*DB, error) { 32 // https://github.com/mattn/go-sqlite3#connection-string 33 opts := []string{ 34 "_foreign_keys=1", ··· 37 "_auto_vacuum=incremental", 38 } 39 40 + logger := log.FromContext(ctx) 41 + logger = log.SubLogger(logger, "db") 42 + 43 db, err := sql.Open("sqlite3", dbPath+"?"+strings.Join(opts, "&")) 44 if err != nil { 45 return nil, err 46 } 47 48 conn, err := db.Conn(ctx) 49 if err != nil { ··· 577 } 578 579 // run migrations 580 + runMigration(conn, logger, "add-description-to-repos", func(tx *sql.Tx) error { 581 tx.Exec(` 582 alter table repos add column description text check (length(description) <= 200); 583 `) 584 return nil 585 }) 586 587 + runMigration(conn, logger, "add-rkey-to-pubkeys", func(tx *sql.Tx) error { 588 // add unconstrained column 589 _, err := tx.Exec(` 590 alter table public_keys ··· 607 return nil 608 }) 609 610 + runMigration(conn, logger, "add-rkey-to-comments", func(tx *sql.Tx) error { 611 _, err := tx.Exec(` 612 alter table comments drop column comment_at; 613 alter table comments add column rkey text; ··· 615 return err 616 }) 617 618 + runMigration(conn, logger, "add-deleted-and-edited-to-issue-comments", func(tx *sql.Tx) error { 619 _, err := tx.Exec(` 620 alter table comments add column deleted text; -- timestamp 621 alter table comments add column edited text; -- timestamp ··· 623 return err 624 }) 625 626 + runMigration(conn, logger, "add-source-info-to-pulls-and-submissions", func(tx *sql.Tx) error { 627 _, err := tx.Exec(` 628 alter table pulls add column source_branch text; 629 alter table pulls add column source_repo_at text; ··· 632 return err 633 }) 634 635 + runMigration(conn, logger, "add-source-to-repos", func(tx *sql.Tx) error { 636 _, err := tx.Exec(` 637 alter table repos add column source text; 638 `) ··· 644 // 645 // [0]: https://sqlite.org/pragma.html#pragma_foreign_keys 646 conn.ExecContext(ctx, "pragma foreign_keys = off;") 647 + runMigration(conn, logger, "recreate-pulls-column-for-stacking-support", func(tx *sql.Tx) error { 648 _, err := tx.Exec(` 649 create table pulls_new ( 650 -- identifiers ··· 701 }) 702 conn.ExecContext(ctx, "pragma foreign_keys = on;") 703 704 + runMigration(conn, logger, "add-spindle-to-repos", func(tx *sql.Tx) error { 705 tx.Exec(` 706 alter table repos add column spindle text; 707 `) ··· 711 // drop all knot secrets, add unique constraint to knots 712 // 713 // knots will henceforth use service auth for signed requests 714 + runMigration(conn, logger, "no-more-secrets", func(tx *sql.Tx) error { 715 _, err := tx.Exec(` 716 create table registrations_new ( 717 id integer primary key autoincrement, ··· 734 }) 735 736 // recreate and add rkey + created columns with default constraint 737 + runMigration(conn, logger, "rework-collaborators-table", func(tx *sql.Tx) error { 738 // create new table 739 // - repo_at instead of repo integer 740 // - rkey field ··· 788 return err 789 }) 790 791 + runMigration(conn, logger, "add-rkey-to-issues", func(tx *sql.Tx) error { 792 _, err := tx.Exec(` 793 alter table issues add column rkey text not null default ''; 794 ··· 800 }) 801 802 // repurpose the read-only column to "needs-upgrade" 803 + runMigration(conn, logger, "rename-registrations-read-only-to-needs-upgrade", func(tx *sql.Tx) error { 804 _, err := tx.Exec(` 805 alter table registrations rename column read_only to needs_upgrade; 806 `) ··· 808 }) 809 810 // require all knots to upgrade after the release of total xrpc 811 + runMigration(conn, logger, "migrate-knots-to-total-xrpc", func(tx *sql.Tx) error { 812 _, err := tx.Exec(` 813 update registrations set needs_upgrade = 1; 814 `) ··· 816 }) 817 818 // require all knots to upgrade after the release of total xrpc 819 + runMigration(conn, logger, "migrate-spindles-to-xrpc-owner", func(tx *sql.Tx) error { 820 _, err := tx.Exec(` 821 alter table spindles add column needs_upgrade integer not null default 0; 822 `) ··· 834 // 835 // disable foreign-keys for the next migration 836 conn.ExecContext(ctx, "pragma foreign_keys = off;") 837 + runMigration(conn, logger, "remove-issue-at-from-issues", func(tx *sql.Tx) error { 838 _, err := tx.Exec(` 839 create table if not exists issues_new ( 840 -- identifiers ··· 904 // - new columns 905 // * column "reply_to" which can be any other comment 906 // * column "at-uri" which is a generated column 907 + runMigration(conn, logger, "rework-issue-comments", func(tx *sql.Tx) error { 908 _, err := tx.Exec(` 909 create table if not exists issue_comments ( 910 -- identifiers ··· 964 // 965 // disable foreign-keys for the next migration 966 conn.ExecContext(ctx, "pragma foreign_keys = off;") 967 + runMigration(conn, logger, "add-at-uri-to-pulls", func(tx *sql.Tx) error { 968 _, err := tx.Exec(` 969 create table if not exists pulls_new ( 970 -- identifiers ··· 1045 // 1046 // disable foreign-keys for the next migration 1047 conn.ExecContext(ctx, "pragma foreign_keys = off;") 1048 + runMigration(conn, logger, "remove-repo-at-pull-id-from-pull-submissions", func(tx *sql.Tx) error { 1049 _, err := tx.Exec(` 1050 create table if not exists pull_submissions_new ( 1051 -- identifiers ··· 1097 }) 1098 conn.ExecContext(ctx, "pragma foreign_keys = on;") 1099 1100 + return &DB{ 1101 + db, 1102 + logger, 1103 + }, nil 1104 } 1105 1106 type migrationFn = func(*sql.Tx) error 1107 1108 + func runMigration(c *sql.Conn, logger *slog.Logger, name string, migrationFn migrationFn) error { 1109 + logger = logger.With("migration", name) 1110 + 1111 tx, err := c.BeginTx(context.Background(), nil) 1112 if err != nil { 1113 return err ··· 1124 // run migration 1125 err = migrationFn(tx) 1126 if err != nil { 1127 + logger.Error("failed to run migration", "err", err) 1128 return err 1129 } 1130 1131 // mark migration as complete 1132 _, err = tx.Exec("insert into migrations (name) values (?)", name) 1133 if err != nil { 1134 + logger.Error("failed to mark migration as complete", "err", err) 1135 return err 1136 } 1137 ··· 1140 return err 1141 } 1142 1143 + logger.Info("migration applied successfully") 1144 } else { 1145 + logger.Warn("skipped migration, already applied") 1146 } 1147 1148 return nil
+1 -1
appview/ingester.go
··· 89 } 90 91 if err != nil { 92 - l.Debug("error ingesting record", "err", err) 93 } 94 95 return nil
··· 89 } 90 91 if err != nil { 92 + l.Warn("refused to ingest record", "err", err) 93 } 94 95 return nil
+27 -26
appview/issues/issues.go
··· 5 "database/sql" 6 "errors" 7 "fmt" 8 - "log" 9 "log/slog" 10 "net/http" 11 "slices" ··· 28 "tangled.org/core/appview/reporesolver" 29 "tangled.org/core/appview/validator" 30 "tangled.org/core/idresolver" 31 - tlog "tangled.org/core/log" 32 "tangled.org/core/tid" 33 ) 34 ··· 53 config *config.Config, 54 notifier notify.Notifier, 55 validator *validator.Validator, 56 ) *Issues { 57 return &Issues{ 58 oauth: oauth, ··· 62 db: db, 63 config: config, 64 notifier: notifier, 65 - logger: tlog.New("issues"), 66 validator: validator, 67 } 68 } ··· 72 user := rp.oauth.GetUser(r) 73 f, err := rp.repoResolver.Resolve(r) 74 if err != nil { 75 - log.Println("failed to get repo and knot", err) 76 return 77 } 78 ··· 99 db.FilterContains("scope", tangled.RepoIssueNSID), 100 ) 101 if err != nil { 102 - log.Println("failed to fetch labels", err) 103 rp.pages.Error503(w) 104 return 105 } ··· 126 user := rp.oauth.GetUser(r) 127 f, err := rp.repoResolver.Resolve(r) 128 if err != nil { 129 - log.Println("failed to get repo and knot", err) 130 return 131 } 132 ··· 199 200 err = db.PutIssue(tx, newIssue) 201 if err != nil { 202 - log.Println("failed to edit issue", err) 203 rp.pages.Notice(w, "issues", "Failed to edit issue.") 204 return 205 } ··· 237 // delete from PDS 238 client, err := rp.oauth.AuthorizedClient(r) 239 if err != nil { 240 - log.Println("failed to get authorized client", err) 241 rp.pages.Notice(w, "issue-comment", "Failed to delete comment.") 242 return 243 } ··· 282 283 collaborators, err := f.Collaborators(r.Context()) 284 if err != nil { 285 - log.Println("failed to fetch repo collaborators: %w", err) 286 } 287 isCollaborator := slices.ContainsFunc(collaborators, func(collab pages.Collaborator) bool { 288 return user.Did == collab.Did ··· 296 db.FilterEq("id", issue.Id), 297 ) 298 if err != nil { 299 - log.Println("failed to close issue", err) 300 rp.pages.Notice(w, "issue-action", "Failed to close issue. Try again later.") 301 return 302 } ··· 307 rp.pages.HxLocation(w, fmt.Sprintf("/%s/issues/%d", f.OwnerSlashRepo(), issue.IssueId)) 308 return 309 } else { 310 - log.Println("user is not permitted to close issue") 311 http.Error(w, "for biden", http.StatusUnauthorized) 312 return 313 } ··· 318 user := rp.oauth.GetUser(r) 319 f, err := rp.repoResolver.Resolve(r) 320 if err != nil { 321 - log.Println("failed to get repo and knot", err) 322 return 323 } 324 ··· 331 332 collaborators, err := f.Collaborators(r.Context()) 333 if err != nil { 334 - log.Println("failed to fetch repo collaborators: %w", err) 335 } 336 isCollaborator := slices.ContainsFunc(collaborators, func(collab pages.Collaborator) bool { 337 return user.Did == collab.Did ··· 344 db.FilterEq("id", issue.Id), 345 ) 346 if err != nil { 347 - log.Println("failed to reopen issue", err) 348 rp.pages.Notice(w, "issue-action", "Failed to reopen issue. Try again later.") 349 return 350 } 351 rp.pages.HxLocation(w, fmt.Sprintf("/%s/issues/%d", f.OwnerSlashRepo(), issue.IssueId)) 352 return 353 } else { 354 - log.Println("user is not the owner of the repo") 355 http.Error(w, "forbidden", http.StatusUnauthorized) 356 return 357 } ··· 538 newBody := r.FormValue("body") 539 client, err := rp.oauth.AuthorizedClient(r) 540 if err != nil { 541 - log.Println("failed to get authorized client", err) 542 rp.pages.Notice(w, "issue-comment", "Failed to create comment.") 543 return 544 } ··· 551 552 _, err = db.AddIssueComment(rp.db, newComment) 553 if err != nil { 554 - log.Println("failed to perferom update-description query", err) 555 rp.pages.Notice(w, "repo-notice", "Failed to update description, try again later.") 556 return 557 } ··· 561 // update the record on pds 562 ex, err := comatproto.RepoGetRecord(r.Context(), client, "", tangled.RepoIssueCommentNSID, user.Did, comment.Rkey) 563 if err != nil { 564 - log.Println("failed to get record", "err", err, "did", newComment.Did, "rkey", newComment.Rkey) 565 rp.pages.Notice(w, fmt.Sprintf("comment-%s-status", commentId), "Failed to update description, no record found on PDS.") 566 return 567 } ··· 729 if comment.Rkey != "" { 730 client, err := rp.oauth.AuthorizedClient(r) 731 if err != nil { 732 - log.Println("failed to get authorized client", err) 733 rp.pages.Notice(w, "issue-comment", "Failed to delete comment.") 734 return 735 } ··· 739 Rkey: comment.Rkey, 740 }) 741 if err != nil { 742 - log.Println(err) 743 } 744 } 745 ··· 757 } 758 759 func (rp *Issues) RepoIssues(w http.ResponseWriter, r *http.Request) { 760 params := r.URL.Query() 761 state := params.Get("state") 762 isOpen := true ··· 771 772 page, ok := r.Context().Value("page").(pagination.Page) 773 if !ok { 774 - log.Println("failed to get page") 775 page = pagination.FirstPage() 776 } 777 778 user := rp.oauth.GetUser(r) 779 f, err := rp.repoResolver.Resolve(r) 780 if err != nil { 781 - log.Println("failed to get repo and knot", err) 782 return 783 } 784 ··· 793 db.FilterEq("open", openVal), 794 ) 795 if err != nil { 796 - log.Println("failed to get issues", err) 797 rp.pages.Notice(w, "issues", "Failed to load issues. Try again later.") 798 return 799 } ··· 804 db.FilterContains("scope", tangled.RepoIssueNSID), 805 ) 806 if err != nil { 807 - log.Println("failed to fetch labels", err) 808 rp.pages.Error503(w) 809 return 810 } ··· 901 902 err = db.PutIssue(tx, issue) 903 if err != nil { 904 - log.Println("failed to create issue", err) 905 rp.pages.Notice(w, "issues", "Failed to create issue.") 906 return 907 } 908 909 if err = tx.Commit(); err != nil { 910 - log.Println("failed to create issue", err) 911 rp.pages.Notice(w, "issues", "Failed to create issue.") 912 return 913 }
··· 5 "database/sql" 6 "errors" 7 "fmt" 8 "log/slog" 9 "net/http" 10 "slices" ··· 27 "tangled.org/core/appview/reporesolver" 28 "tangled.org/core/appview/validator" 29 "tangled.org/core/idresolver" 30 "tangled.org/core/tid" 31 ) 32 ··· 51 config *config.Config, 52 notifier notify.Notifier, 53 validator *validator.Validator, 54 + logger *slog.Logger, 55 ) *Issues { 56 return &Issues{ 57 oauth: oauth, ··· 61 db: db, 62 config: config, 63 notifier: notifier, 64 + logger: logger, 65 validator: validator, 66 } 67 } ··· 71 user := rp.oauth.GetUser(r) 72 f, err := rp.repoResolver.Resolve(r) 73 if err != nil { 74 + l.Error("failed to get repo and knot", "err", err) 75 return 76 } 77 ··· 98 db.FilterContains("scope", tangled.RepoIssueNSID), 99 ) 100 if err != nil { 101 + l.Error("failed to fetch labels", "err", err) 102 rp.pages.Error503(w) 103 return 104 } ··· 125 user := rp.oauth.GetUser(r) 126 f, err := rp.repoResolver.Resolve(r) 127 if err != nil { 128 + l.Error("failed to get repo and knot", "err", err) 129 return 130 } 131 ··· 198 199 err = db.PutIssue(tx, newIssue) 200 if err != nil { 201 + l.Error("failed to edit issue", "err", err) 202 rp.pages.Notice(w, "issues", "Failed to edit issue.") 203 return 204 } ··· 236 // delete from PDS 237 client, err := rp.oauth.AuthorizedClient(r) 238 if err != nil { 239 + l.Error("failed to get authorized client", "err", err) 240 rp.pages.Notice(w, "issue-comment", "Failed to delete comment.") 241 return 242 } ··· 281 282 collaborators, err := f.Collaborators(r.Context()) 283 if err != nil { 284 + l.Error("failed to fetch repo collaborators", "err", err) 285 } 286 isCollaborator := slices.ContainsFunc(collaborators, func(collab pages.Collaborator) bool { 287 return user.Did == collab.Did ··· 295 db.FilterEq("id", issue.Id), 296 ) 297 if err != nil { 298 + l.Error("failed to close issue", "err", err) 299 rp.pages.Notice(w, "issue-action", "Failed to close issue. Try again later.") 300 return 301 } ··· 306 rp.pages.HxLocation(w, fmt.Sprintf("/%s/issues/%d", f.OwnerSlashRepo(), issue.IssueId)) 307 return 308 } else { 309 + l.Error("user is not permitted to close issue") 310 http.Error(w, "for biden", http.StatusUnauthorized) 311 return 312 } ··· 317 user := rp.oauth.GetUser(r) 318 f, err := rp.repoResolver.Resolve(r) 319 if err != nil { 320 + l.Error("failed to get repo and knot", "err", err) 321 return 322 } 323 ··· 330 331 collaborators, err := f.Collaborators(r.Context()) 332 if err != nil { 333 + l.Error("failed to fetch repo collaborators", "err", err) 334 } 335 isCollaborator := slices.ContainsFunc(collaborators, func(collab pages.Collaborator) bool { 336 return user.Did == collab.Did ··· 343 db.FilterEq("id", issue.Id), 344 ) 345 if err != nil { 346 + l.Error("failed to reopen issue", "err", err) 347 rp.pages.Notice(w, "issue-action", "Failed to reopen issue. Try again later.") 348 return 349 } 350 rp.pages.HxLocation(w, fmt.Sprintf("/%s/issues/%d", f.OwnerSlashRepo(), issue.IssueId)) 351 return 352 } else { 353 + l.Error("user is not the owner of the repo") 354 http.Error(w, "forbidden", http.StatusUnauthorized) 355 return 356 } ··· 537 newBody := r.FormValue("body") 538 client, err := rp.oauth.AuthorizedClient(r) 539 if err != nil { 540 + l.Error("failed to get authorized client", "err", err) 541 rp.pages.Notice(w, "issue-comment", "Failed to create comment.") 542 return 543 } ··· 550 551 _, err = db.AddIssueComment(rp.db, newComment) 552 if err != nil { 553 + l.Error("failed to perferom update-description query", "err", err) 554 rp.pages.Notice(w, "repo-notice", "Failed to update description, try again later.") 555 return 556 } ··· 560 // update the record on pds 561 ex, err := comatproto.RepoGetRecord(r.Context(), client, "", tangled.RepoIssueCommentNSID, user.Did, comment.Rkey) 562 if err != nil { 563 + l.Error("failed to get record", "err", err, "did", newComment.Did, "rkey", newComment.Rkey) 564 rp.pages.Notice(w, fmt.Sprintf("comment-%s-status", commentId), "Failed to update description, no record found on PDS.") 565 return 566 } ··· 728 if comment.Rkey != "" { 729 client, err := rp.oauth.AuthorizedClient(r) 730 if err != nil { 731 + l.Error("failed to get authorized client", "err", err) 732 rp.pages.Notice(w, "issue-comment", "Failed to delete comment.") 733 return 734 } ··· 738 Rkey: comment.Rkey, 739 }) 740 if err != nil { 741 + l.Error("failed to delete from PDS", "err", err) 742 } 743 } 744 ··· 756 } 757 758 func (rp *Issues) RepoIssues(w http.ResponseWriter, r *http.Request) { 759 + l := rp.logger.With("handler", "RepoIssues") 760 + 761 params := r.URL.Query() 762 state := params.Get("state") 763 isOpen := true ··· 772 773 page, ok := r.Context().Value("page").(pagination.Page) 774 if !ok { 775 + l.Error("failed to get page") 776 page = pagination.FirstPage() 777 } 778 779 user := rp.oauth.GetUser(r) 780 f, err := rp.repoResolver.Resolve(r) 781 if err != nil { 782 + l.Error("failed to get repo and knot", "err", err) 783 return 784 } 785 ··· 794 db.FilterEq("open", openVal), 795 ) 796 if err != nil { 797 + l.Error("failed to get issues", "err", err) 798 rp.pages.Notice(w, "issues", "Failed to load issues. Try again later.") 799 return 800 } ··· 805 db.FilterContains("scope", tangled.RepoIssueNSID), 806 ) 807 if err != nil { 808 + l.Error("failed to fetch labels", "err", err) 809 rp.pages.Error503(w) 810 return 811 } ··· 902 903 err = db.PutIssue(tx, issue) 904 if err != nil { 905 + l.Error("failed to create issue", "err", err) 906 rp.pages.Notice(w, "issues", "Failed to create issue.") 907 return 908 } 909 910 if err = tx.Commit(); err != nil { 911 + l.Error("failed to create issue", "err", err) 912 rp.pages.Notice(w, "issues", "Failed to create issue.") 913 return 914 }
+1 -3
appview/labels/labels.go
··· 16 "tangled.org/core/appview/oauth" 17 "tangled.org/core/appview/pages" 18 "tangled.org/core/appview/validator" 19 - "tangled.org/core/log" 20 "tangled.org/core/rbac" 21 "tangled.org/core/tid" 22 ··· 42 db *db.DB, 43 validator *validator.Validator, 44 enforcer *rbac.Enforcer, 45 ) *Labels { 46 - logger := log.New("labels") 47 - 48 return &Labels{ 49 oauth: oauth, 50 pages: pages,
··· 16 "tangled.org/core/appview/oauth" 17 "tangled.org/core/appview/pages" 18 "tangled.org/core/appview/validator" 19 "tangled.org/core/rbac" 20 "tangled.org/core/tid" 21 ··· 41 db *db.DB, 42 validator *validator.Validator, 43 enforcer *rbac.Enforcer, 44 + logger *slog.Logger, 45 ) *Labels { 46 return &Labels{ 47 oauth: oauth, 48 pages: pages,
+15 -12
appview/notifications/notifications.go
··· 1 package notifications 2 3 import ( 4 - "log" 5 "net/http" 6 "strconv" 7 ··· 14 ) 15 16 type Notifications struct { 17 - db *db.DB 18 - oauth *oauth.OAuth 19 - pages *pages.Pages 20 } 21 22 - func New(database *db.DB, oauthHandler *oauth.OAuth, pagesHandler *pages.Pages) *Notifications { 23 return &Notifications{ 24 - db: database, 25 - oauth: oauthHandler, 26 - pages: pagesHandler, 27 } 28 } 29 ··· 44 } 45 46 func (n *Notifications) notificationsPage(w http.ResponseWriter, r *http.Request) { 47 user := n.oauth.GetUser(r) 48 49 page, ok := r.Context().Value("page").(pagination.Page) 50 if !ok { 51 - log.Println("failed to get page") 52 page = pagination.FirstPage() 53 } 54 ··· 57 db.FilterEq("recipient_did", user.Did), 58 ) 59 if err != nil { 60 - log.Println("failed to get total notifications:", err) 61 n.pages.Error500(w) 62 return 63 } ··· 68 db.FilterEq("recipient_did", user.Did), 69 ) 70 if err != nil { 71 - log.Println("failed to get notifications:", err) 72 n.pages.Error500(w) 73 return 74 } 75 76 err = n.db.MarkAllNotificationsRead(r.Context(), user.Did) 77 if err != nil { 78 - log.Println("failed to mark notifications as read:", err) 79 } 80 81 unreadCount := 0
··· 1 package notifications 2 3 import ( 4 + "log/slog" 5 "net/http" 6 "strconv" 7 ··· 14 ) 15 16 type Notifications struct { 17 + db *db.DB 18 + oauth *oauth.OAuth 19 + pages *pages.Pages 20 + logger *slog.Logger 21 } 22 23 + func New(database *db.DB, oauthHandler *oauth.OAuth, pagesHandler *pages.Pages, logger *slog.Logger) *Notifications { 24 return &Notifications{ 25 + db: database, 26 + oauth: oauthHandler, 27 + pages: pagesHandler, 28 + logger: logger, 29 } 30 } 31 ··· 46 } 47 48 func (n *Notifications) notificationsPage(w http.ResponseWriter, r *http.Request) { 49 + l := n.logger.With("handler", "notificationsPage") 50 user := n.oauth.GetUser(r) 51 52 page, ok := r.Context().Value("page").(pagination.Page) 53 if !ok { 54 + l.Error("failed to get page") 55 page = pagination.FirstPage() 56 } 57 ··· 60 db.FilterEq("recipient_did", user.Did), 61 ) 62 if err != nil { 63 + l.Error("failed to get total notifications", "err", err) 64 n.pages.Error500(w) 65 return 66 } ··· 71 db.FilterEq("recipient_did", user.Did), 72 ) 73 if err != nil { 74 + l.Error("failed to get notifications", "err", err) 75 n.pages.Error500(w) 76 return 77 } 78 79 err = n.db.MarkAllNotificationsRead(r.Context(), user.Did) 80 if err != nil { 81 + l.Error("failed to mark notifications as read", "err", err) 82 } 83 84 unreadCount := 0
+2 -2
appview/pages/pages.go
··· 54 logger *slog.Logger 55 } 56 57 - func NewPages(config *config.Config, res *idresolver.Resolver) *Pages { 58 // initialized with safe defaults, can be overriden per use 59 rctx := &markup.RenderContext{ 60 IsDev: config.Core.Dev, ··· 72 rctx: rctx, 73 resolver: res, 74 templateDir: "appview/pages", 75 - logger: slog.Default().With("component", "pages"), 76 } 77 78 if p.dev {
··· 54 logger *slog.Logger 55 } 56 57 + func NewPages(config *config.Config, res *idresolver.Resolver, logger *slog.Logger) *Pages { 58 // initialized with safe defaults, can be overriden per use 59 rctx := &markup.RenderContext{ 60 IsDev: config.Core.Dev, ··· 72 rctx: rctx, 73 resolver: res, 74 templateDir: "appview/pages", 75 + logger: logger, 76 } 77 78 if p.dev {
+1 -3
appview/pipelines/pipelines.go
··· 16 "tangled.org/core/appview/reporesolver" 17 "tangled.org/core/eventconsumer" 18 "tangled.org/core/idresolver" 19 - "tangled.org/core/log" 20 "tangled.org/core/rbac" 21 spindlemodel "tangled.org/core/spindle/models" 22 ··· 45 db *db.DB, 46 config *config.Config, 47 enforcer *rbac.Enforcer, 48 ) *Pipelines { 49 - logger := log.New("pipelines") 50 - 51 return &Pipelines{ 52 oauth: oauth, 53 repoResolver: repoResolver,
··· 16 "tangled.org/core/appview/reporesolver" 17 "tangled.org/core/eventconsumer" 18 "tangled.org/core/idresolver" 19 "tangled.org/core/rbac" 20 spindlemodel "tangled.org/core/spindle/models" 21 ··· 44 db *db.DB, 45 config *config.Config, 46 enforcer *rbac.Enforcer, 47 + logger *slog.Logger, 48 ) *Pipelines { 49 return &Pipelines{ 50 oauth: oauth, 51 repoResolver: repoResolver,
+4
appview/pulls/pulls.go
··· 6 "errors" 7 "fmt" 8 "log" 9 "net/http" 10 "slices" 11 "sort" ··· 46 config *config.Config 47 notifier notify.Notifier 48 enforcer *rbac.Enforcer 49 } 50 51 func New( ··· 57 config *config.Config, 58 notifier notify.Notifier, 59 enforcer *rbac.Enforcer, 60 ) *Pulls { 61 return &Pulls{ 62 oauth: oauth, ··· 67 config: config, 68 notifier: notifier, 69 enforcer: enforcer, 70 } 71 } 72
··· 6 "errors" 7 "fmt" 8 "log" 9 + "log/slog" 10 "net/http" 11 "slices" 12 "sort" ··· 47 config *config.Config 48 notifier notify.Notifier 49 enforcer *rbac.Enforcer 50 + logger *slog.Logger 51 } 52 53 func New( ··· 59 config *config.Config, 60 notifier notify.Notifier, 61 enforcer *rbac.Enforcer, 62 + logger *slog.Logger, 63 ) *Pulls { 64 return &Pulls{ 65 oauth: oauth, ··· 70 config: config, 71 notifier: notifier, 72 enforcer: enforcer, 73 + logger: logger, 74 } 75 } 76
+14 -11
appview/repo/index.go
··· 3 import ( 4 "errors" 5 "fmt" 6 - "log" 7 "net/http" 8 "net/url" 9 "slices" ··· 31 ) 32 33 func (rp *Repo) RepoIndex(w http.ResponseWriter, r *http.Request) { 34 ref := chi.URLParam(r, "ref") 35 ref, _ = url.PathUnescape(ref) 36 37 f, err := rp.repoResolver.Resolve(r) 38 if err != nil { 39 - log.Println("failed to fully resolve repo", err) 40 return 41 } 42 ··· 56 result, err := rp.buildIndexResponse(r.Context(), xrpcc, f, ref) 57 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 58 if errors.Is(xrpcerr, xrpcclient.ErrXrpcUnsupported) { 59 - log.Println("failed to call XRPC repo.index", err) 60 rp.pages.RepoIndexPage(w, pages.RepoIndexParams{ 61 LoggedInUser: user, 62 NeedsKnotUpgrade: true, ··· 66 } 67 68 rp.pages.Error503(w) 69 - log.Println("failed to build index response", err) 70 return 71 } 72 ··· 119 emails := uniqueEmails(commitsTrunc) 120 emailToDidMap, err := db.GetEmailToDid(rp.db, emails, true) 121 if err != nil { 122 - log.Println("failed to get email to did map", err) 123 } 124 125 vc, err := commitverify.GetVerifiedObjectCommits(rp.db, emailToDidMap, commitsTrunc) 126 if err != nil { 127 - log.Println(err) 128 } 129 130 // TODO: a bit dirty 131 - languageInfo, err := rp.getLanguageInfo(r.Context(), f, xrpcc, result.Ref, ref == "") 132 if err != nil { 133 - log.Printf("failed to compute language percentages: %s", err) 134 // non-fatal 135 } 136 ··· 140 } 141 pipelines, err := getPipelineStatuses(rp.db, repoInfo, shas) 142 if err != nil { 143 - log.Printf("failed to fetch pipeline statuses: %s", err) 144 // non-fatal 145 } 146 ··· 162 163 func (rp *Repo) getLanguageInfo( 164 ctx context.Context, 165 f *reporesolver.ResolvedRepo, 166 xrpcc *indigoxrpc.Client, 167 currentRef string, ··· 180 ls, err := tangled.RepoLanguages(ctx, xrpcc, currentRef, repo) 181 if err != nil { 182 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 183 - log.Println("failed to call XRPC repo.languages", xrpcerr) 184 return nil, xrpcerr 185 } 186 return nil, err ··· 210 err = db.UpdateRepoLanguages(tx, f.RepoAt(), currentRef, langs) 211 if err != nil { 212 // non-fatal 213 - log.Println("failed to cache lang results", err) 214 } 215 216 err = tx.Commit()
··· 3 import ( 4 "errors" 5 "fmt" 6 + "log/slog" 7 "net/http" 8 "net/url" 9 "slices" ··· 31 ) 32 33 func (rp *Repo) RepoIndex(w http.ResponseWriter, r *http.Request) { 34 + l := rp.logger.With("handler", "RepoIndex") 35 + 36 ref := chi.URLParam(r, "ref") 37 ref, _ = url.PathUnescape(ref) 38 39 f, err := rp.repoResolver.Resolve(r) 40 if err != nil { 41 + l.Error("failed to fully resolve repo", "err", err) 42 return 43 } 44 ··· 58 result, err := rp.buildIndexResponse(r.Context(), xrpcc, f, ref) 59 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 60 if errors.Is(xrpcerr, xrpcclient.ErrXrpcUnsupported) { 61 + l.Error("failed to call XRPC repo.index", "err", err) 62 rp.pages.RepoIndexPage(w, pages.RepoIndexParams{ 63 LoggedInUser: user, 64 NeedsKnotUpgrade: true, ··· 68 } 69 70 rp.pages.Error503(w) 71 + l.Error("failed to build index response", "err", err) 72 return 73 } 74 ··· 121 emails := uniqueEmails(commitsTrunc) 122 emailToDidMap, err := db.GetEmailToDid(rp.db, emails, true) 123 if err != nil { 124 + l.Error("failed to get email to did map", "err", err) 125 } 126 127 vc, err := commitverify.GetVerifiedObjectCommits(rp.db, emailToDidMap, commitsTrunc) 128 if err != nil { 129 + l.Error("failed to GetVerifiedObjectCommits", "err", err) 130 } 131 132 // TODO: a bit dirty 133 + languageInfo, err := rp.getLanguageInfo(r.Context(), l, f, xrpcc, result.Ref, ref == "") 134 if err != nil { 135 + l.Warn("failed to compute language percentages", "err", err) 136 // non-fatal 137 } 138 ··· 142 } 143 pipelines, err := getPipelineStatuses(rp.db, repoInfo, shas) 144 if err != nil { 145 + l.Error("failed to fetch pipeline statuses", "err", err) 146 // non-fatal 147 } 148 ··· 164 165 func (rp *Repo) getLanguageInfo( 166 ctx context.Context, 167 + l *slog.Logger, 168 f *reporesolver.ResolvedRepo, 169 xrpcc *indigoxrpc.Client, 170 currentRef string, ··· 183 ls, err := tangled.RepoLanguages(ctx, xrpcc, currentRef, repo) 184 if err != nil { 185 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 186 + l.Error("failed to call XRPC repo.languages", "err", xrpcerr) 187 return nil, xrpcerr 188 } 189 return nil, err ··· 213 err = db.UpdateRepoLanguages(tx, f.RepoAt(), currentRef, langs) 214 if err != nil { 215 // non-fatal 216 + l.Error("failed to cache lang results", "err", err) 217 } 218 219 err = tx.Commit()
+130 -92
appview/repo/repo.go
··· 7 "errors" 8 "fmt" 9 "io" 10 - "log" 11 "log/slog" 12 "net/http" 13 "net/url" ··· 90 } 91 92 func (rp *Repo) DownloadArchive(w http.ResponseWriter, r *http.Request) { 93 ref := chi.URLParam(r, "ref") 94 ref, _ = url.PathUnescape(ref) 95 96 f, err := rp.repoResolver.Resolve(r) 97 if err != nil { 98 - log.Println("failed to get repo and knot", err) 99 return 100 } 101 ··· 111 repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name) 112 archiveBytes, err := tangled.RepoArchive(r.Context(), xrpcc, "tar.gz", "", ref, repo) 113 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 114 - log.Println("failed to call XRPC repo.archive", xrpcerr) 115 rp.pages.Error503(w) 116 return 117 } ··· 128 } 129 130 func (rp *Repo) RepoLog(w http.ResponseWriter, r *http.Request) { 131 f, err := rp.repoResolver.Resolve(r) 132 if err != nil { 133 - log.Println("failed to fully resolve repo", err) 134 return 135 } 136 ··· 165 repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name) 166 xrpcBytes, err := tangled.RepoLog(r.Context(), xrpcc, cursor, limit, "", ref, repo) 167 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 168 - log.Println("failed to call XRPC repo.log", xrpcerr) 169 rp.pages.Error503(w) 170 return 171 } 172 173 var xrpcResp types.RepoLogResponse 174 if err := json.Unmarshal(xrpcBytes, &xrpcResp); err != nil { 175 - log.Println("failed to decode XRPC response", err) 176 rp.pages.Error503(w) 177 return 178 } 179 180 tagBytes, err := tangled.RepoTags(r.Context(), xrpcc, "", 0, repo) 181 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 182 - log.Println("failed to call XRPC repo.tags", xrpcerr) 183 rp.pages.Error503(w) 184 return 185 } ··· 196 197 branchBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo) 198 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 199 - log.Println("failed to call XRPC repo.branches", xrpcerr) 200 rp.pages.Error503(w) 201 return 202 } ··· 214 215 emailToDidMap, err := db.GetEmailToDid(rp.db, uniqueEmails(xrpcResp.Commits), true) 216 if err != nil { 217 - log.Println("failed to fetch email to did mapping", err) 218 } 219 220 vc, err := commitverify.GetVerifiedObjectCommits(rp.db, emailToDidMap, xrpcResp.Commits) 221 if err != nil { 222 - log.Println(err) 223 } 224 225 repoInfo := f.RepoInfo(user) ··· 230 } 231 pipelines, err := getPipelineStatuses(rp.db, repoInfo, shas) 232 if err != nil { 233 - log.Println(err) 234 // non-fatal 235 } 236 ··· 246 } 247 248 func (rp *Repo) RepoDescriptionEdit(w http.ResponseWriter, r *http.Request) { 249 f, err := rp.repoResolver.Resolve(r) 250 if err != nil { 251 - log.Println("failed to get repo and knot", err) 252 w.WriteHeader(http.StatusBadRequest) 253 return 254 } ··· 260 } 261 262 func (rp *Repo) RepoDescription(w http.ResponseWriter, r *http.Request) { 263 f, err := rp.repoResolver.Resolve(r) 264 if err != nil { 265 - log.Println("failed to get repo and knot", err) 266 w.WriteHeader(http.StatusBadRequest) 267 return 268 } ··· 270 repoAt := f.RepoAt() 271 rkey := repoAt.RecordKey().String() 272 if rkey == "" { 273 - log.Println("invalid aturi for repo", err) 274 w.WriteHeader(http.StatusInternalServerError) 275 return 276 } ··· 287 newDescription := r.FormValue("description") 288 client, err := rp.oauth.AuthorizedClient(r) 289 if err != nil { 290 - log.Println("failed to get client") 291 rp.pages.Notice(w, "repo-notice", "Failed to update description, try again later.") 292 return 293 } ··· 295 // optimistic update 296 err = db.UpdateDescription(rp.db, string(repoAt), newDescription) 297 if err != nil { 298 - log.Println("failed to perferom update-description query", err) 299 rp.pages.Notice(w, "repo-notice", "Failed to update description, try again later.") 300 return 301 } ··· 324 }) 325 326 if err != nil { 327 - log.Println("failed to perferom update-description query", err) 328 // failed to get record 329 rp.pages.Notice(w, "repo-notice", "Failed to update description, unable to save to PDS.") 330 return ··· 341 } 342 343 func (rp *Repo) RepoCommit(w http.ResponseWriter, r *http.Request) { 344 f, err := rp.repoResolver.Resolve(r) 345 if err != nil { 346 - log.Println("failed to fully resolve repo", err) 347 return 348 } 349 ref := chi.URLParam(r, "ref") ··· 371 repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name) 372 xrpcBytes, err := tangled.RepoDiff(r.Context(), xrpcc, ref, repo) 373 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 374 - log.Println("failed to call XRPC repo.diff", xrpcerr) 375 rp.pages.Error503(w) 376 return 377 } 378 379 var result types.RepoCommitResponse 380 if err := json.Unmarshal(xrpcBytes, &result); err != nil { 381 - log.Println("failed to decode XRPC response", err) 382 rp.pages.Error503(w) 383 return 384 } 385 386 emailToDidMap, err := db.GetEmailToDid(rp.db, []string{result.Diff.Commit.Committer.Email, result.Diff.Commit.Author.Email}, true) 387 if err != nil { 388 - log.Println("failed to get email to did mapping:", err) 389 } 390 391 vc, err := commitverify.GetVerifiedCommits(rp.db, emailToDidMap, []types.NiceDiff{*result.Diff}) 392 if err != nil { 393 - log.Println(err) 394 } 395 396 user := rp.oauth.GetUser(r) 397 repoInfo := f.RepoInfo(user) 398 pipelines, err := getPipelineStatuses(rp.db, repoInfo, []string{result.Diff.Commit.This}) 399 if err != nil { 400 - log.Println(err) 401 // non-fatal 402 } 403 var pipeline *models.Pipeline ··· 417 } 418 419 func (rp *Repo) RepoTree(w http.ResponseWriter, r *http.Request) { 420 f, err := rp.repoResolver.Resolve(r) 421 if err != nil { 422 - log.Println("failed to fully resolve repo", err) 423 return 424 } 425 ··· 444 repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name) 445 xrpcResp, err := tangled.RepoTree(r.Context(), xrpcc, treePath, ref, repo) 446 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 447 - log.Println("failed to call XRPC repo.tree", xrpcerr) 448 rp.pages.Error503(w) 449 return 450 } ··· 519 } 520 521 func (rp *Repo) RepoTags(w http.ResponseWriter, r *http.Request) { 522 f, err := rp.repoResolver.Resolve(r) 523 if err != nil { 524 - log.Println("failed to get repo and knot", err) 525 return 526 } 527 ··· 537 repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name) 538 xrpcBytes, err := tangled.RepoTags(r.Context(), xrpcc, "", 0, repo) 539 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 540 - log.Println("failed to call XRPC repo.tags", xrpcerr) 541 rp.pages.Error503(w) 542 return 543 } 544 545 var result types.RepoTagsResponse 546 if err := json.Unmarshal(xrpcBytes, &result); err != nil { 547 - log.Println("failed to decode XRPC response", err) 548 rp.pages.Error503(w) 549 return 550 } 551 552 artifacts, err := db.GetArtifact(rp.db, db.FilterEq("repo_at", f.RepoAt())) 553 if err != nil { 554 - log.Println("failed grab artifacts", err) 555 return 556 } 557 ··· 588 } 589 590 func (rp *Repo) RepoBranches(w http.ResponseWriter, r *http.Request) { 591 f, err := rp.repoResolver.Resolve(r) 592 if err != nil { 593 - log.Println("failed to get repo and knot", err) 594 return 595 } 596 ··· 606 repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name) 607 xrpcBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo) 608 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 609 - log.Println("failed to call XRPC repo.branches", xrpcerr) 610 rp.pages.Error503(w) 611 return 612 } 613 614 var result types.RepoBranchesResponse 615 if err := json.Unmarshal(xrpcBytes, &result); err != nil { 616 - log.Println("failed to decode XRPC response", err) 617 rp.pages.Error503(w) 618 return 619 } ··· 629 } 630 631 func (rp *Repo) DeleteBranch(w http.ResponseWriter, r *http.Request) { 632 f, err := rp.repoResolver.Resolve(r) 633 if err != nil { 634 - log.Println("failed to get repo and knot", err) 635 return 636 } 637 638 noticeId := "delete-branch-error" 639 fail := func(msg string, err error) { 640 - log.Println(msg, "err", err) 641 rp.pages.Notice(w, noticeId, msg) 642 } 643 ··· 670 fail(fmt.Sprintf("Failed to delete branch: %s", err), err) 671 return 672 } 673 - log.Println("deleted branch from knot", "branch", branch, "repo", f.RepoAt()) 674 675 rp.pages.HxRefresh(w) 676 } 677 678 func (rp *Repo) RepoBlob(w http.ResponseWriter, r *http.Request) { 679 f, err := rp.repoResolver.Resolve(r) 680 if err != nil { 681 - log.Println("failed to get repo and knot", err) 682 return 683 } 684 ··· 700 repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Repo.Name) 701 resp, err := tangled.RepoBlob(r.Context(), xrpcc, filePath, false, ref, repo) 702 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 703 - log.Println("failed to call XRPC repo.blob", xrpcerr) 704 rp.pages.Error503(w) 705 return 706 } ··· 800 } 801 802 func (rp *Repo) RepoBlobRaw(w http.ResponseWriter, r *http.Request) { 803 f, err := rp.repoResolver.Resolve(r) 804 if err != nil { 805 - log.Println("failed to get repo and knot", err) 806 w.WriteHeader(http.StatusBadRequest) 807 return 808 } ··· 834 835 req, err := http.NewRequest("GET", blobURL, nil) 836 if err != nil { 837 - log.Println("failed to create request", err) 838 return 839 } 840 ··· 846 client := &http.Client{} 847 resp, err := client.Do(req) 848 if err != nil { 849 - log.Println("failed to reach knotserver", err) 850 rp.pages.Error503(w) 851 return 852 } ··· 859 } 860 861 if resp.StatusCode != http.StatusOK { 862 - log.Printf("knotserver returned non-OK status for raw blob %s: %d", blobURL, resp.StatusCode) 863 w.WriteHeader(resp.StatusCode) 864 _, _ = io.Copy(w, resp.Body) 865 return ··· 868 contentType := resp.Header.Get("Content-Type") 869 body, err := io.ReadAll(resp.Body) 870 if err != nil { 871 - log.Printf("error reading response body from knotserver: %v", err) 872 w.WriteHeader(http.StatusInternalServerError) 873 return 874 } ··· 1443 db.FilterContains("scope", subject.Collection().String()), 1444 ) 1445 if err != nil { 1446 - log.Println("failed to fetch label defs", err) 1447 return 1448 } 1449 ··· 1454 1455 states, err := db.GetLabels(rp.db, db.FilterEq("subject", subject)) 1456 if err != nil { 1457 - log.Println("failed to build label state", err) 1458 return 1459 } 1460 state := states[subject] ··· 1491 db.FilterContains("scope", subject.Collection().String()), 1492 ) 1493 if err != nil { 1494 - log.Println("failed to fetch labels", err) 1495 return 1496 } 1497 ··· 1502 1503 states, err := db.GetLabels(rp.db, db.FilterEq("subject", subject)) 1504 if err != nil { 1505 - log.Println("failed to build label state", err) 1506 return 1507 } 1508 state := states[subject] ··· 1649 1650 func (rp *Repo) DeleteRepo(w http.ResponseWriter, r *http.Request) { 1651 user := rp.oauth.GetUser(r) 1652 1653 noticeId := "operation-error" 1654 f, err := rp.repoResolver.Resolve(r) 1655 if err != nil { 1656 - log.Println("failed to get repo and knot", err) 1657 return 1658 } 1659 1660 // remove record from pds 1661 atpClient, err := rp.oauth.AuthorizedClient(r) 1662 if err != nil { 1663 - log.Println("failed to get authorized client", err) 1664 return 1665 } 1666 _, err = comatproto.RepoDeleteRecord(r.Context(), atpClient, &comatproto.RepoDeleteRecord_Input{ ··· 1669 Rkey: f.Rkey, 1670 }) 1671 if err != nil { 1672 - log.Printf("failed to delete record: %s", err) 1673 rp.pages.Notice(w, noticeId, "Failed to delete repository from PDS.") 1674 return 1675 } 1676 - log.Println("removed repo record ", f.RepoAt().String()) 1677 1678 client, err := rp.oauth.ServiceClient( 1679 r, ··· 1682 oauth.WithDev(rp.config.Core.Dev), 1683 ) 1684 if err != nil { 1685 - log.Println("failed to connect to knot server:", err) 1686 return 1687 } 1688 ··· 1699 rp.pages.Notice(w, noticeId, err.Error()) 1700 return 1701 } 1702 - log.Println("deleted repo from knot") 1703 1704 tx, err := rp.db.BeginTx(r.Context(), nil) 1705 if err != nil { 1706 - log.Println("failed to start tx") 1707 w.Write(fmt.Append(nil, "failed to add collaborator: ", err)) 1708 return 1709 } ··· 1711 tx.Rollback() 1712 err = rp.enforcer.E.LoadPolicy() 1713 if err != nil { 1714 - log.Println("failed to rollback policies") 1715 } 1716 }() 1717 ··· 1725 did := c[0] 1726 rp.enforcer.RemoveCollaborator(did, f.Knot, f.DidSlashRepo()) 1727 } 1728 - log.Println("removed collaborators") 1729 1730 // remove repo RBAC 1731 err = rp.enforcer.RemoveRepo(f.OwnerDid(), f.Knot, f.DidSlashRepo()) ··· 1740 rp.pages.Notice(w, noticeId, "Failed to update appview") 1741 return 1742 } 1743 - log.Println("removed repo from db") 1744 1745 err = tx.Commit() 1746 if err != nil { 1747 - log.Println("failed to commit changes", err) 1748 http.Error(w, err.Error(), http.StatusInternalServerError) 1749 return 1750 } 1751 1752 err = rp.enforcer.E.SavePolicy() 1753 if err != nil { 1754 - log.Println("failed to update ACLs", err) 1755 http.Error(w, err.Error(), http.StatusInternalServerError) 1756 return 1757 } ··· 1760 } 1761 1762 func (rp *Repo) SetDefaultBranch(w http.ResponseWriter, r *http.Request) { 1763 f, err := rp.repoResolver.Resolve(r) 1764 if err != nil { 1765 - log.Println("failed to get repo and knot", err) 1766 return 1767 } 1768 ··· 1780 oauth.WithDev(rp.config.Core.Dev), 1781 ) 1782 if err != nil { 1783 - log.Println("failed to connect to knot server:", err) 1784 rp.pages.Notice(w, noticeId, "Failed to connect to knot server.") 1785 return 1786 } ··· 1794 }, 1795 ) 1796 if err := xrpcclient.HandleXrpcErr(xe); err != nil { 1797 - log.Println("xrpc failed", "err", xe) 1798 rp.pages.Notice(w, noticeId, err.Error()) 1799 return 1800 } ··· 1809 1810 f, err := rp.repoResolver.Resolve(r) 1811 if err != nil { 1812 - log.Println("failed to get repo and knot", err) 1813 return 1814 } 1815 1816 if f.Spindle == "" { 1817 - log.Println("empty spindle cannot add/rm secret", err) 1818 return 1819 } 1820 ··· 1831 oauth.WithDev(rp.config.Core.Dev), 1832 ) 1833 if err != nil { 1834 - log.Println("failed to create spindle client", err) 1835 return 1836 } 1837 ··· 1917 } 1918 1919 func (rp *Repo) generalSettings(w http.ResponseWriter, r *http.Request) { 1920 f, err := rp.repoResolver.Resolve(r) 1921 user := rp.oauth.GetUser(r) 1922 ··· 1932 repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name) 1933 xrpcBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo) 1934 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 1935 - log.Println("failed to call XRPC repo.branches", xrpcerr) 1936 rp.pages.Error503(w) 1937 return 1938 } 1939 1940 var result types.RepoBranchesResponse 1941 if err := json.Unmarshal(xrpcBytes, &result); err != nil { 1942 - log.Println("failed to decode XRPC response", err) 1943 rp.pages.Error503(w) 1944 return 1945 } 1946 1947 defaultLabels, err := db.GetLabelDefinitions(rp.db, db.FilterIn("at_uri", models.DefaultLabelDefs())) 1948 if err != nil { 1949 - log.Println("failed to fetch labels", err) 1950 rp.pages.Error503(w) 1951 return 1952 } 1953 1954 labels, err := db.GetLabelDefinitions(rp.db, db.FilterIn("at_uri", f.Repo.Labels)) 1955 if err != nil { 1956 - log.Println("failed to fetch labels", err) 1957 rp.pages.Error503(w) 1958 return 1959 } ··· 2001 } 2002 2003 func (rp *Repo) accessSettings(w http.ResponseWriter, r *http.Request) { 2004 f, err := rp.repoResolver.Resolve(r) 2005 user := rp.oauth.GetUser(r) 2006 2007 repoCollaborators, err := f.Collaborators(r.Context()) 2008 if err != nil { 2009 - log.Println("failed to get collaborators", err) 2010 } 2011 2012 rp.pages.RepoAccessSettings(w, pages.RepoAccessSettingsParams{ ··· 2019 } 2020 2021 func (rp *Repo) pipelineSettings(w http.ResponseWriter, r *http.Request) { 2022 f, err := rp.repoResolver.Resolve(r) 2023 user := rp.oauth.GetUser(r) 2024 2025 // all spindles that the repo owner is a member of 2026 spindles, err := rp.enforcer.GetSpindlesForUser(f.OwnerDid()) 2027 if err != nil { 2028 - log.Println("failed to fetch spindles", err) 2029 return 2030 } 2031 ··· 2038 oauth.WithExp(60), 2039 oauth.WithDev(rp.config.Core.Dev), 2040 ); err != nil { 2041 - log.Println("failed to create spindle client", err) 2042 } else if resp, err := tangled.RepoListSecrets(r.Context(), spindleClient, f.RepoAt().String()); err != nil { 2043 - log.Println("failed to fetch secrets", err) 2044 } else { 2045 secrets = resp.Secrets 2046 } ··· 2080 } 2081 2082 func (rp *Repo) SyncRepoFork(w http.ResponseWriter, r *http.Request) { 2083 ref := chi.URLParam(r, "ref") 2084 ref, _ = url.PathUnescape(ref) 2085 2086 user := rp.oauth.GetUser(r) 2087 f, err := rp.repoResolver.Resolve(r) 2088 if err != nil { 2089 - log.Printf("failed to resolve source repo: %v", err) 2090 return 2091 } 2092 ··· 2130 } 2131 2132 func (rp *Repo) ForkRepo(w http.ResponseWriter, r *http.Request) { 2133 user := rp.oauth.GetUser(r) 2134 f, err := rp.repoResolver.Resolve(r) 2135 if err != nil { 2136 - log.Printf("failed to resolve source repo: %v", err) 2137 return 2138 } 2139 ··· 2184 ) 2185 if err != nil { 2186 if !errors.Is(err, sql.ErrNoRows) { 2187 - log.Println("error fetching existing repo from db", "err", err) 2188 rp.pages.Notice(w, "repo", "Failed to fork this repository. Try again later.") 2189 return 2190 } ··· 2299 2300 err = db.AddRepo(tx, repo) 2301 if err != nil { 2302 - log.Println(err) 2303 rp.pages.Notice(w, "repo", "Failed to save repository information.") 2304 return 2305 } ··· 2308 p, _ := securejoin.SecureJoin(user.Did, forkName) 2309 err = rp.enforcer.AddRepo(user.Did, targetKnot, p) 2310 if err != nil { 2311 - log.Println(err) 2312 rp.pages.Notice(w, "repo", "Failed to set up repository permissions.") 2313 return 2314 } 2315 2316 err = tx.Commit() 2317 if err != nil { 2318 - log.Println("failed to commit changes", err) 2319 http.Error(w, err.Error(), http.StatusInternalServerError) 2320 return 2321 } 2322 2323 err = rp.enforcer.E.SavePolicy() 2324 if err != nil { 2325 - log.Println("failed to update ACLs", err) 2326 http.Error(w, err.Error(), http.StatusInternalServerError) 2327 return 2328 } ··· 2358 } 2359 2360 func (rp *Repo) RepoCompareNew(w http.ResponseWriter, r *http.Request) { 2361 user := rp.oauth.GetUser(r) 2362 f, err := rp.repoResolver.Resolve(r) 2363 if err != nil { 2364 - log.Println("failed to get repo and knot", err) 2365 return 2366 } 2367 ··· 2377 repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name) 2378 branchBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo) 2379 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 2380 - log.Println("failed to call XRPC repo.branches", xrpcerr) 2381 rp.pages.Error503(w) 2382 return 2383 } 2384 2385 var branchResult types.RepoBranchesResponse 2386 if err := json.Unmarshal(branchBytes, &branchResult); err != nil { 2387 - log.Println("failed to decode XRPC branches response", err) 2388 rp.pages.Notice(w, "compare-error", "Failed to produce comparison. Try again later.") 2389 return 2390 } ··· 2414 2415 tagBytes, err := tangled.RepoTags(r.Context(), xrpcc, "", 0, repo) 2416 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 2417 - log.Println("failed to call XRPC repo.tags", xrpcerr) 2418 rp.pages.Error503(w) 2419 return 2420 } 2421 2422 var tags types.RepoTagsResponse 2423 if err := json.Unmarshal(tagBytes, &tags); err != nil { 2424 - log.Println("failed to decode XRPC tags response", err) 2425 rp.pages.Notice(w, "compare-error", "Failed to produce comparison. Try again later.") 2426 return 2427 } ··· 2439 } 2440 2441 func (rp *Repo) RepoCompare(w http.ResponseWriter, r *http.Request) { 2442 user := rp.oauth.GetUser(r) 2443 f, err := rp.repoResolver.Resolve(r) 2444 if err != nil { 2445 - log.Println("failed to get repo and knot", err) 2446 return 2447 } 2448 ··· 2469 head, _ = url.PathUnescape(head) 2470 2471 if base == "" || head == "" { 2472 - log.Printf("invalid comparison") 2473 rp.pages.Error404(w) 2474 return 2475 } ··· 2487 2488 branchBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo) 2489 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 2490 - log.Println("failed to call XRPC repo.branches", xrpcerr) 2491 rp.pages.Error503(w) 2492 return 2493 } 2494 2495 var branches types.RepoBranchesResponse 2496 if err := json.Unmarshal(branchBytes, &branches); err != nil { 2497 - log.Println("failed to decode XRPC branches response", err) 2498 rp.pages.Notice(w, "compare-error", "Failed to produce comparison. Try again later.") 2499 return 2500 } 2501 2502 tagBytes, err := tangled.RepoTags(r.Context(), xrpcc, "", 0, repo) 2503 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 2504 - log.Println("failed to call XRPC repo.tags", xrpcerr) 2505 rp.pages.Error503(w) 2506 return 2507 } 2508 2509 var tags types.RepoTagsResponse 2510 if err := json.Unmarshal(tagBytes, &tags); err != nil { 2511 - log.Println("failed to decode XRPC tags response", err) 2512 rp.pages.Notice(w, "compare-error", "Failed to produce comparison. Try again later.") 2513 return 2514 } 2515 2516 compareBytes, err := tangled.RepoCompare(r.Context(), xrpcc, repo, base, head) 2517 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 2518 - log.Println("failed to call XRPC repo.compare", xrpcerr) 2519 rp.pages.Error503(w) 2520 return 2521 } 2522 2523 var formatPatch types.RepoFormatPatchResponse 2524 if err := json.Unmarshal(compareBytes, &formatPatch); err != nil { 2525 - log.Println("failed to decode XRPC compare response", err) 2526 rp.pages.Notice(w, "compare-error", "Failed to produce comparison. Try again later.") 2527 return 2528 }
··· 7 "errors" 8 "fmt" 9 "io" 10 "log/slog" 11 "net/http" 12 "net/url" ··· 89 } 90 91 func (rp *Repo) DownloadArchive(w http.ResponseWriter, r *http.Request) { 92 + l := rp.logger.With("handler", "DownloadArchive") 93 + 94 ref := chi.URLParam(r, "ref") 95 ref, _ = url.PathUnescape(ref) 96 97 f, err := rp.repoResolver.Resolve(r) 98 if err != nil { 99 + l.Error("failed to get repo and knot", "err", err) 100 return 101 } 102 ··· 112 repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name) 113 archiveBytes, err := tangled.RepoArchive(r.Context(), xrpcc, "tar.gz", "", ref, repo) 114 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 115 + l.Error("failed to call XRPC repo.archive", "err", xrpcerr) 116 rp.pages.Error503(w) 117 return 118 } ··· 129 } 130 131 func (rp *Repo) RepoLog(w http.ResponseWriter, r *http.Request) { 132 + l := rp.logger.With("handler", "RepoLog") 133 + 134 f, err := rp.repoResolver.Resolve(r) 135 if err != nil { 136 + l.Error("failed to fully resolve repo", "err", err) 137 return 138 } 139 ··· 168 repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name) 169 xrpcBytes, err := tangled.RepoLog(r.Context(), xrpcc, cursor, limit, "", ref, repo) 170 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 171 + l.Error("failed to call XRPC repo.log", "err", xrpcerr) 172 rp.pages.Error503(w) 173 return 174 } 175 176 var xrpcResp types.RepoLogResponse 177 if err := json.Unmarshal(xrpcBytes, &xrpcResp); err != nil { 178 + l.Error("failed to decode XRPC response", "err", err) 179 rp.pages.Error503(w) 180 return 181 } 182 183 tagBytes, err := tangled.RepoTags(r.Context(), xrpcc, "", 0, repo) 184 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 185 + l.Error("failed to call XRPC repo.tags", "err", xrpcerr) 186 rp.pages.Error503(w) 187 return 188 } ··· 199 200 branchBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo) 201 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 202 + l.Error("failed to call XRPC repo.branches", "err", xrpcerr) 203 rp.pages.Error503(w) 204 return 205 } ··· 217 218 emailToDidMap, err := db.GetEmailToDid(rp.db, uniqueEmails(xrpcResp.Commits), true) 219 if err != nil { 220 + l.Error("failed to fetch email to did mapping", "err", err) 221 } 222 223 vc, err := commitverify.GetVerifiedObjectCommits(rp.db, emailToDidMap, xrpcResp.Commits) 224 if err != nil { 225 + l.Error("failed to GetVerifiedObjectCommits", "err", err) 226 } 227 228 repoInfo := f.RepoInfo(user) ··· 233 } 234 pipelines, err := getPipelineStatuses(rp.db, repoInfo, shas) 235 if err != nil { 236 + l.Error("failed to getPipelineStatuses", "err", err) 237 // non-fatal 238 } 239 ··· 249 } 250 251 func (rp *Repo) RepoDescriptionEdit(w http.ResponseWriter, r *http.Request) { 252 + l := rp.logger.With("handler", "RepoDescriptionEdit") 253 + 254 f, err := rp.repoResolver.Resolve(r) 255 if err != nil { 256 + l.Error("failed to get repo and knot", "err", err) 257 w.WriteHeader(http.StatusBadRequest) 258 return 259 } ··· 265 } 266 267 func (rp *Repo) RepoDescription(w http.ResponseWriter, r *http.Request) { 268 + l := rp.logger.With("handler", "RepoDescription") 269 + 270 f, err := rp.repoResolver.Resolve(r) 271 if err != nil { 272 + l.Error("failed to get repo and knot", "err", err) 273 w.WriteHeader(http.StatusBadRequest) 274 return 275 } ··· 277 repoAt := f.RepoAt() 278 rkey := repoAt.RecordKey().String() 279 if rkey == "" { 280 + l.Error("invalid aturi for repo", "err", err) 281 w.WriteHeader(http.StatusInternalServerError) 282 return 283 } ··· 294 newDescription := r.FormValue("description") 295 client, err := rp.oauth.AuthorizedClient(r) 296 if err != nil { 297 + l.Error("failed to get client") 298 rp.pages.Notice(w, "repo-notice", "Failed to update description, try again later.") 299 return 300 } ··· 302 // optimistic update 303 err = db.UpdateDescription(rp.db, string(repoAt), newDescription) 304 if err != nil { 305 + l.Error("failed to perform update-description query", "err", err) 306 rp.pages.Notice(w, "repo-notice", "Failed to update description, try again later.") 307 return 308 } ··· 331 }) 332 333 if err != nil { 334 + l.Error("failed to perferom update-description query", "err", err) 335 // failed to get record 336 rp.pages.Notice(w, "repo-notice", "Failed to update description, unable to save to PDS.") 337 return ··· 348 } 349 350 func (rp *Repo) RepoCommit(w http.ResponseWriter, r *http.Request) { 351 + l := rp.logger.With("handler", "RepoCommit") 352 + 353 f, err := rp.repoResolver.Resolve(r) 354 if err != nil { 355 + l.Error("failed to fully resolve repo", "err", err) 356 return 357 } 358 ref := chi.URLParam(r, "ref") ··· 380 repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name) 381 xrpcBytes, err := tangled.RepoDiff(r.Context(), xrpcc, ref, repo) 382 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 383 + l.Error("failed to call XRPC repo.diff", "err", xrpcerr) 384 rp.pages.Error503(w) 385 return 386 } 387 388 var result types.RepoCommitResponse 389 if err := json.Unmarshal(xrpcBytes, &result); err != nil { 390 + l.Error("failed to decode XRPC response", "err", err) 391 rp.pages.Error503(w) 392 return 393 } 394 395 emailToDidMap, err := db.GetEmailToDid(rp.db, []string{result.Diff.Commit.Committer.Email, result.Diff.Commit.Author.Email}, true) 396 if err != nil { 397 + l.Error("failed to get email to did mapping", "err", err) 398 } 399 400 vc, err := commitverify.GetVerifiedCommits(rp.db, emailToDidMap, []types.NiceDiff{*result.Diff}) 401 if err != nil { 402 + l.Error("failed to GetVerifiedCommits", "err", err) 403 } 404 405 user := rp.oauth.GetUser(r) 406 repoInfo := f.RepoInfo(user) 407 pipelines, err := getPipelineStatuses(rp.db, repoInfo, []string{result.Diff.Commit.This}) 408 if err != nil { 409 + l.Error("failed to getPipelineStatuses", "err", err) 410 // non-fatal 411 } 412 var pipeline *models.Pipeline ··· 426 } 427 428 func (rp *Repo) RepoTree(w http.ResponseWriter, r *http.Request) { 429 + l := rp.logger.With("handler", "RepoTree") 430 + 431 f, err := rp.repoResolver.Resolve(r) 432 if err != nil { 433 + l.Error("failed to fully resolve repo", "err", err) 434 return 435 } 436 ··· 455 repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name) 456 xrpcResp, err := tangled.RepoTree(r.Context(), xrpcc, treePath, ref, repo) 457 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 458 + l.Error("failed to call XRPC repo.tree", "err", xrpcerr) 459 rp.pages.Error503(w) 460 return 461 } ··· 530 } 531 532 func (rp *Repo) RepoTags(w http.ResponseWriter, r *http.Request) { 533 + l := rp.logger.With("handler", "RepoTags") 534 + 535 f, err := rp.repoResolver.Resolve(r) 536 if err != nil { 537 + l.Error("failed to get repo and knot", "err", err) 538 return 539 } 540 ··· 550 repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name) 551 xrpcBytes, err := tangled.RepoTags(r.Context(), xrpcc, "", 0, repo) 552 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 553 + l.Error("failed to call XRPC repo.tags", "err", xrpcerr) 554 rp.pages.Error503(w) 555 return 556 } 557 558 var result types.RepoTagsResponse 559 if err := json.Unmarshal(xrpcBytes, &result); err != nil { 560 + l.Error("failed to decode XRPC response", "err", err) 561 rp.pages.Error503(w) 562 return 563 } 564 565 artifacts, err := db.GetArtifact(rp.db, db.FilterEq("repo_at", f.RepoAt())) 566 if err != nil { 567 + l.Error("failed grab artifacts", "err", err) 568 return 569 } 570 ··· 601 } 602 603 func (rp *Repo) RepoBranches(w http.ResponseWriter, r *http.Request) { 604 + l := rp.logger.With("handler", "RepoBranches") 605 + 606 f, err := rp.repoResolver.Resolve(r) 607 if err != nil { 608 + l.Error("failed to get repo and knot", "err", err) 609 return 610 } 611 ··· 621 repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name) 622 xrpcBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo) 623 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 624 + l.Error("failed to call XRPC repo.branches", "err", xrpcerr) 625 rp.pages.Error503(w) 626 return 627 } 628 629 var result types.RepoBranchesResponse 630 if err := json.Unmarshal(xrpcBytes, &result); err != nil { 631 + l.Error("failed to decode XRPC response", "err", err) 632 rp.pages.Error503(w) 633 return 634 } ··· 644 } 645 646 func (rp *Repo) DeleteBranch(w http.ResponseWriter, r *http.Request) { 647 + l := rp.logger.With("handler", "DeleteBranch") 648 + 649 f, err := rp.repoResolver.Resolve(r) 650 if err != nil { 651 + l.Error("failed to get repo and knot", "err", err) 652 return 653 } 654 655 noticeId := "delete-branch-error" 656 fail := func(msg string, err error) { 657 + l.Error(msg, "err", err) 658 rp.pages.Notice(w, noticeId, msg) 659 } 660 ··· 687 fail(fmt.Sprintf("Failed to delete branch: %s", err), err) 688 return 689 } 690 + l.Error("deleted branch from knot", "branch", branch, "repo", f.RepoAt()) 691 692 rp.pages.HxRefresh(w) 693 } 694 695 func (rp *Repo) RepoBlob(w http.ResponseWriter, r *http.Request) { 696 + l := rp.logger.With("handler", "RepoBlob") 697 + 698 f, err := rp.repoResolver.Resolve(r) 699 if err != nil { 700 + l.Error("failed to get repo and knot", "err", err) 701 return 702 } 703 ··· 719 repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Repo.Name) 720 resp, err := tangled.RepoBlob(r.Context(), xrpcc, filePath, false, ref, repo) 721 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 722 + l.Error("failed to call XRPC repo.blob", "err", xrpcerr) 723 rp.pages.Error503(w) 724 return 725 } ··· 819 } 820 821 func (rp *Repo) RepoBlobRaw(w http.ResponseWriter, r *http.Request) { 822 + l := rp.logger.With("handler", "RepoBlobRaw") 823 + 824 f, err := rp.repoResolver.Resolve(r) 825 if err != nil { 826 + l.Error("failed to get repo and knot", err) 827 w.WriteHeader(http.StatusBadRequest) 828 return 829 } ··· 855 856 req, err := http.NewRequest("GET", blobURL, nil) 857 if err != nil { 858 + l.Error("failed to create request", "err", err) 859 return 860 } 861 ··· 867 client := &http.Client{} 868 resp, err := client.Do(req) 869 if err != nil { 870 + l.Error("failed to reach knotserver", "err", err) 871 rp.pages.Error503(w) 872 return 873 } ··· 880 } 881 882 if resp.StatusCode != http.StatusOK { 883 + l.Error("knotserver returned non-OK status for raw blob", "url", blobURL, "statuscode", resp.StatusCode) 884 w.WriteHeader(resp.StatusCode) 885 _, _ = io.Copy(w, resp.Body) 886 return ··· 889 contentType := resp.Header.Get("Content-Type") 890 body, err := io.ReadAll(resp.Body) 891 if err != nil { 892 + l.Error("error reading response body from knotserver", "err", err) 893 w.WriteHeader(http.StatusInternalServerError) 894 return 895 } ··· 1464 db.FilterContains("scope", subject.Collection().String()), 1465 ) 1466 if err != nil { 1467 + l.Error("failed to fetch label defs", "err", err) 1468 return 1469 } 1470 ··· 1475 1476 states, err := db.GetLabels(rp.db, db.FilterEq("subject", subject)) 1477 if err != nil { 1478 + l.Error("failed to build label state", "err", err) 1479 return 1480 } 1481 state := states[subject] ··· 1512 db.FilterContains("scope", subject.Collection().String()), 1513 ) 1514 if err != nil { 1515 + l.Error("failed to fetch labels", "err", err) 1516 return 1517 } 1518 ··· 1523 1524 states, err := db.GetLabels(rp.db, db.FilterEq("subject", subject)) 1525 if err != nil { 1526 + l.Error("failed to build label state", "err", err) 1527 return 1528 } 1529 state := states[subject] ··· 1670 1671 func (rp *Repo) DeleteRepo(w http.ResponseWriter, r *http.Request) { 1672 user := rp.oauth.GetUser(r) 1673 + l := rp.logger.With("handler", "DeleteRepo") 1674 1675 noticeId := "operation-error" 1676 f, err := rp.repoResolver.Resolve(r) 1677 if err != nil { 1678 + l.Error("failed to get repo and knot", "err", err) 1679 return 1680 } 1681 1682 // remove record from pds 1683 atpClient, err := rp.oauth.AuthorizedClient(r) 1684 if err != nil { 1685 + l.Error("failed to get authorized client", "err", err) 1686 return 1687 } 1688 _, err = comatproto.RepoDeleteRecord(r.Context(), atpClient, &comatproto.RepoDeleteRecord_Input{ ··· 1691 Rkey: f.Rkey, 1692 }) 1693 if err != nil { 1694 + l.Error("failed to delete record", "err", err) 1695 rp.pages.Notice(w, noticeId, "Failed to delete repository from PDS.") 1696 return 1697 } 1698 + l.Info("removed repo record", "aturi", f.RepoAt().String()) 1699 1700 client, err := rp.oauth.ServiceClient( 1701 r, ··· 1704 oauth.WithDev(rp.config.Core.Dev), 1705 ) 1706 if err != nil { 1707 + l.Error("failed to connect to knot server", "err", err) 1708 return 1709 } 1710 ··· 1721 rp.pages.Notice(w, noticeId, err.Error()) 1722 return 1723 } 1724 + l.Info("deleted repo from knot") 1725 1726 tx, err := rp.db.BeginTx(r.Context(), nil) 1727 if err != nil { 1728 + l.Error("failed to start tx") 1729 w.Write(fmt.Append(nil, "failed to add collaborator: ", err)) 1730 return 1731 } ··· 1733 tx.Rollback() 1734 err = rp.enforcer.E.LoadPolicy() 1735 if err != nil { 1736 + l.Error("failed to rollback policies") 1737 } 1738 }() 1739 ··· 1747 did := c[0] 1748 rp.enforcer.RemoveCollaborator(did, f.Knot, f.DidSlashRepo()) 1749 } 1750 + l.Info("removed collaborators") 1751 1752 // remove repo RBAC 1753 err = rp.enforcer.RemoveRepo(f.OwnerDid(), f.Knot, f.DidSlashRepo()) ··· 1762 rp.pages.Notice(w, noticeId, "Failed to update appview") 1763 return 1764 } 1765 + l.Info("removed repo from db") 1766 1767 err = tx.Commit() 1768 if err != nil { 1769 + l.Error("failed to commit changes", "err", err) 1770 http.Error(w, err.Error(), http.StatusInternalServerError) 1771 return 1772 } 1773 1774 err = rp.enforcer.E.SavePolicy() 1775 if err != nil { 1776 + l.Error("failed to update ACLs", "err", err) 1777 http.Error(w, err.Error(), http.StatusInternalServerError) 1778 return 1779 } ··· 1782 } 1783 1784 func (rp *Repo) SetDefaultBranch(w http.ResponseWriter, r *http.Request) { 1785 + l := rp.logger.With("handler", "SetDefaultBranch") 1786 + 1787 f, err := rp.repoResolver.Resolve(r) 1788 if err != nil { 1789 + l.Error("failed to get repo and knot", "err", err) 1790 return 1791 } 1792 ··· 1804 oauth.WithDev(rp.config.Core.Dev), 1805 ) 1806 if err != nil { 1807 + l.Error("failed to connect to knot server", "err", err) 1808 rp.pages.Notice(w, noticeId, "Failed to connect to knot server.") 1809 return 1810 } ··· 1818 }, 1819 ) 1820 if err := xrpcclient.HandleXrpcErr(xe); err != nil { 1821 + l.Error("xrpc failed", "err", xe) 1822 rp.pages.Notice(w, noticeId, err.Error()) 1823 return 1824 } ··· 1833 1834 f, err := rp.repoResolver.Resolve(r) 1835 if err != nil { 1836 + l.Error("failed to get repo and knot", "err", err) 1837 return 1838 } 1839 1840 if f.Spindle == "" { 1841 + l.Error("empty spindle cannot add/rm secret", "err", err) 1842 return 1843 } 1844 ··· 1855 oauth.WithDev(rp.config.Core.Dev), 1856 ) 1857 if err != nil { 1858 + l.Error("failed to create spindle client", "err", err) 1859 return 1860 } 1861 ··· 1941 } 1942 1943 func (rp *Repo) generalSettings(w http.ResponseWriter, r *http.Request) { 1944 + l := rp.logger.With("handler", "generalSettings") 1945 + 1946 f, err := rp.repoResolver.Resolve(r) 1947 user := rp.oauth.GetUser(r) 1948 ··· 1958 repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name) 1959 xrpcBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo) 1960 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 1961 + l.Error("failed to call XRPC repo.branches", "err", xrpcerr) 1962 rp.pages.Error503(w) 1963 return 1964 } 1965 1966 var result types.RepoBranchesResponse 1967 if err := json.Unmarshal(xrpcBytes, &result); err != nil { 1968 + l.Error("failed to decode XRPC response", "err", err) 1969 rp.pages.Error503(w) 1970 return 1971 } 1972 1973 defaultLabels, err := db.GetLabelDefinitions(rp.db, db.FilterIn("at_uri", models.DefaultLabelDefs())) 1974 if err != nil { 1975 + l.Error("failed to fetch labels", "err", err) 1976 rp.pages.Error503(w) 1977 return 1978 } 1979 1980 labels, err := db.GetLabelDefinitions(rp.db, db.FilterIn("at_uri", f.Repo.Labels)) 1981 if err != nil { 1982 + l.Error("failed to fetch labels", "err", err) 1983 rp.pages.Error503(w) 1984 return 1985 } ··· 2027 } 2028 2029 func (rp *Repo) accessSettings(w http.ResponseWriter, r *http.Request) { 2030 + l := rp.logger.With("handler", "accessSettings") 2031 + 2032 f, err := rp.repoResolver.Resolve(r) 2033 user := rp.oauth.GetUser(r) 2034 2035 repoCollaborators, err := f.Collaborators(r.Context()) 2036 if err != nil { 2037 + l.Error("failed to get collaborators", "err", err) 2038 } 2039 2040 rp.pages.RepoAccessSettings(w, pages.RepoAccessSettingsParams{ ··· 2047 } 2048 2049 func (rp *Repo) pipelineSettings(w http.ResponseWriter, r *http.Request) { 2050 + l := rp.logger.With("handler", "pipelineSettings") 2051 + 2052 f, err := rp.repoResolver.Resolve(r) 2053 user := rp.oauth.GetUser(r) 2054 2055 // all spindles that the repo owner is a member of 2056 spindles, err := rp.enforcer.GetSpindlesForUser(f.OwnerDid()) 2057 if err != nil { 2058 + l.Error("failed to fetch spindles", "err", err) 2059 return 2060 } 2061 ··· 2068 oauth.WithExp(60), 2069 oauth.WithDev(rp.config.Core.Dev), 2070 ); err != nil { 2071 + l.Error("failed to create spindle client", "err", err) 2072 } else if resp, err := tangled.RepoListSecrets(r.Context(), spindleClient, f.RepoAt().String()); err != nil { 2073 + l.Error("failed to fetch secrets", "err", err) 2074 } else { 2075 secrets = resp.Secrets 2076 } ··· 2110 } 2111 2112 func (rp *Repo) SyncRepoFork(w http.ResponseWriter, r *http.Request) { 2113 + l := rp.logger.With("handler", "SyncRepoFork") 2114 + 2115 ref := chi.URLParam(r, "ref") 2116 ref, _ = url.PathUnescape(ref) 2117 2118 user := rp.oauth.GetUser(r) 2119 f, err := rp.repoResolver.Resolve(r) 2120 if err != nil { 2121 + l.Error("failed to resolve source repo", "err", err) 2122 return 2123 } 2124 ··· 2162 } 2163 2164 func (rp *Repo) ForkRepo(w http.ResponseWriter, r *http.Request) { 2165 + l := rp.logger.With("handler", "ForkRepo") 2166 + 2167 user := rp.oauth.GetUser(r) 2168 f, err := rp.repoResolver.Resolve(r) 2169 if err != nil { 2170 + l.Error("failed to resolve source repo", "err", err) 2171 return 2172 } 2173 ··· 2218 ) 2219 if err != nil { 2220 if !errors.Is(err, sql.ErrNoRows) { 2221 + l.Error("error fetching existing repo from db", "err", err) 2222 rp.pages.Notice(w, "repo", "Failed to fork this repository. Try again later.") 2223 return 2224 } ··· 2333 2334 err = db.AddRepo(tx, repo) 2335 if err != nil { 2336 + l.Error("failed to AddRepo", "err", err) 2337 rp.pages.Notice(w, "repo", "Failed to save repository information.") 2338 return 2339 } ··· 2342 p, _ := securejoin.SecureJoin(user.Did, forkName) 2343 err = rp.enforcer.AddRepo(user.Did, targetKnot, p) 2344 if err != nil { 2345 + l.Error("failed to add ACLs", "err", err) 2346 rp.pages.Notice(w, "repo", "Failed to set up repository permissions.") 2347 return 2348 } 2349 2350 err = tx.Commit() 2351 if err != nil { 2352 + l.Error("failed to commit changes", "err", err) 2353 http.Error(w, err.Error(), http.StatusInternalServerError) 2354 return 2355 } 2356 2357 err = rp.enforcer.E.SavePolicy() 2358 if err != nil { 2359 + l.Error("failed to update ACLs", "err", err) 2360 http.Error(w, err.Error(), http.StatusInternalServerError) 2361 return 2362 } ··· 2392 } 2393 2394 func (rp *Repo) RepoCompareNew(w http.ResponseWriter, r *http.Request) { 2395 + l := rp.logger.With("handler", "RepoCompareNew") 2396 + 2397 user := rp.oauth.GetUser(r) 2398 f, err := rp.repoResolver.Resolve(r) 2399 if err != nil { 2400 + l.Error("failed to get repo and knot", "err", err) 2401 return 2402 } 2403 ··· 2413 repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name) 2414 branchBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo) 2415 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 2416 + l.Error("failed to call XRPC repo.branches", "err", xrpcerr) 2417 rp.pages.Error503(w) 2418 return 2419 } 2420 2421 var branchResult types.RepoBranchesResponse 2422 if err := json.Unmarshal(branchBytes, &branchResult); err != nil { 2423 + l.Error("failed to decode XRPC branches response", "err", err) 2424 rp.pages.Notice(w, "compare-error", "Failed to produce comparison. Try again later.") 2425 return 2426 } ··· 2450 2451 tagBytes, err := tangled.RepoTags(r.Context(), xrpcc, "", 0, repo) 2452 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 2453 + l.Error("failed to call XRPC repo.tags", "err", xrpcerr) 2454 rp.pages.Error503(w) 2455 return 2456 } 2457 2458 var tags types.RepoTagsResponse 2459 if err := json.Unmarshal(tagBytes, &tags); err != nil { 2460 + l.Error("failed to decode XRPC tags response", "err", err) 2461 rp.pages.Notice(w, "compare-error", "Failed to produce comparison. Try again later.") 2462 return 2463 } ··· 2475 } 2476 2477 func (rp *Repo) RepoCompare(w http.ResponseWriter, r *http.Request) { 2478 + l := rp.logger.With("handler", "RepoCompare") 2479 + 2480 user := rp.oauth.GetUser(r) 2481 f, err := rp.repoResolver.Resolve(r) 2482 if err != nil { 2483 + l.Error("failed to get repo and knot", "err", err) 2484 return 2485 } 2486 ··· 2507 head, _ = url.PathUnescape(head) 2508 2509 if base == "" || head == "" { 2510 + l.Error("invalid comparison") 2511 rp.pages.Error404(w) 2512 return 2513 } ··· 2525 2526 branchBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo) 2527 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 2528 + l.Error("failed to call XRPC repo.branches", "err", xrpcerr) 2529 rp.pages.Error503(w) 2530 return 2531 } 2532 2533 var branches types.RepoBranchesResponse 2534 if err := json.Unmarshal(branchBytes, &branches); err != nil { 2535 + l.Error("failed to decode XRPC branches response", "err", err) 2536 rp.pages.Notice(w, "compare-error", "Failed to produce comparison. Try again later.") 2537 return 2538 } 2539 2540 tagBytes, err := tangled.RepoTags(r.Context(), xrpcc, "", 0, repo) 2541 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 2542 + l.Error("failed to call XRPC repo.tags", "err", xrpcerr) 2543 rp.pages.Error503(w) 2544 return 2545 } 2546 2547 var tags types.RepoTagsResponse 2548 if err := json.Unmarshal(tagBytes, &tags); err != nil { 2549 + l.Error("failed to decode XRPC tags response", "err", err) 2550 rp.pages.Notice(w, "compare-error", "Failed to produce comparison. Try again later.") 2551 return 2552 } 2553 2554 compareBytes, err := tangled.RepoCompare(r.Context(), xrpcc, repo, base, head) 2555 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 2556 + l.Error("failed to call XRPC repo.compare", "err", xrpcerr) 2557 rp.pages.Error503(w) 2558 return 2559 } 2560 2561 var formatPatch types.RepoFormatPatchResponse 2562 if err := json.Unmarshal(compareBytes, &formatPatch); err != nil { 2563 + l.Error("failed to decode XRPC compare response", "err", err) 2564 rp.pages.Notice(w, "compare-error", "Failed to produce comparison. Try again later.") 2565 return 2566 }
+1 -1
appview/signup/signup.go
··· 62 disallowed := make(map[string]bool) 63 64 if filepath == "" { 65 - logger.Debug("no disallowed nicknames file configured") 66 return disallowed 67 } 68
··· 62 disallowed := make(map[string]bool) 63 64 if filepath == "" { 65 + logger.Warn("no disallowed nicknames file configured") 66 return disallowed 67 } 68
+3 -1
appview/state/knotstream.go
··· 25 ) 26 27 func Knotstream(ctx context.Context, c *config.Config, d *db.DB, enforcer *rbac.Enforcer, posthog posthog.Client) (*ec.Consumer, error) { 28 knots, err := db.GetRegistrations( 29 d, 30 db.FilterIsNot("registered", "null"), ··· 39 srcs[s] = struct{}{} 40 } 41 42 - logger := log.New("knotstream") 43 cache := cache.New(c.Redis.Addr) 44 cursorStore := cursor.NewRedisCursorStore(cache) 45
··· 25 ) 26 27 func Knotstream(ctx context.Context, c *config.Config, d *db.DB, enforcer *rbac.Enforcer, posthog posthog.Client) (*ec.Consumer, error) { 28 + logger := log.FromContext(ctx) 29 + logger = log.SubLogger(logger, "knotstream") 30 + 31 knots, err := db.GetRegistrations( 32 d, 33 db.FilterIsNot("registered", "null"), ··· 42 srcs[s] = struct{}{} 43 } 44 45 cache := cache.New(c.Redis.Addr) 46 cursorStore := cursor.NewRedisCursorStore(cache) 47
+7 -4
appview/state/login.go
··· 2 3 import ( 4 "fmt" 5 - "log" 6 "net/http" 7 "strings" 8 ··· 10 ) 11 12 func (s *State) Login(w http.ResponseWriter, r *http.Request) { 13 switch r.Method { 14 case http.MethodGet: 15 returnURL := r.URL.Query().Get("return_url") ··· 32 33 // basic handle validation 34 if !strings.Contains(handle, ".") { 35 - log.Println("invalid handle format", "raw", handle) 36 s.pages.Notice( 37 w, 38 "login-msg", ··· 52 } 53 54 func (s *State) Logout(w http.ResponseWriter, r *http.Request) { 55 err := s.oauth.DeleteSession(w, r) 56 if err != nil { 57 - log.Println("failed to logout", "err", err) 58 } else { 59 - log.Println("logged out successfully") 60 } 61 62 s.pages.HxRedirect(w, "/login")
··· 2 3 import ( 4 "fmt" 5 "net/http" 6 "strings" 7 ··· 9 ) 10 11 func (s *State) Login(w http.ResponseWriter, r *http.Request) { 12 + l := s.logger.With("handler", "Login") 13 + 14 switch r.Method { 15 case http.MethodGet: 16 returnURL := r.URL.Query().Get("return_url") ··· 33 34 // basic handle validation 35 if !strings.Contains(handle, ".") { 36 + l.Error("invalid handle format", "raw", handle) 37 s.pages.Notice( 38 w, 39 "login-msg", ··· 53 } 54 55 func (s *State) Logout(w http.ResponseWriter, r *http.Request) { 56 + l := s.logger.With("handler", "Logout") 57 + 58 err := s.oauth.DeleteSession(w, r) 59 if err != nil { 60 + l.Error("failed to logout", "err", err) 61 } else { 62 + l.Info("logged out successfully") 63 } 64 65 s.pages.HxRedirect(w, "/login")
+59 -13
appview/state/router.go
··· 205 } 206 207 func (s *State) SpindlesRouter() http.Handler { 208 - logger := log.New("spindles") 209 210 spindles := &spindles.Spindles{ 211 Db: s.db, ··· 221 } 222 223 func (s *State) KnotsRouter() http.Handler { 224 - logger := log.New("knots") 225 226 knots := &knots.Knots{ 227 Db: s.db, ··· 238 } 239 240 func (s *State) StringsRouter(mw *middleware.Middleware) http.Handler { 241 - logger := log.New("strings") 242 243 strs := &avstrings.Strings{ 244 Db: s.db, ··· 253 } 254 255 func (s *State) IssuesRouter(mw *middleware.Middleware) http.Handler { 256 - issues := issues.New(s.oauth, s.repoResolver, s.pages, s.idResolver, s.db, s.config, s.notifier, s.validator) 257 return issues.Router(mw) 258 } 259 260 func (s *State) PullsRouter(mw *middleware.Middleware) http.Handler { 261 - pulls := pulls.New(s.oauth, s.repoResolver, s.pages, s.idResolver, s.db, s.config, s.notifier, s.enforcer) 262 return pulls.Router(mw) 263 } 264 265 func (s *State) RepoRouter(mw *middleware.Middleware) http.Handler { 266 - logger := log.New("repo") 267 - repo := repo.New(s.oauth, s.repoResolver, s.pages, s.spindlestream, s.idResolver, s.db, s.config, s.notifier, s.enforcer, logger, s.validator) 268 return repo.Router(mw) 269 } 270 271 func (s *State) PipelinesRouter(mw *middleware.Middleware) http.Handler { 272 - pipes := pipelines.New(s.oauth, s.repoResolver, s.pages, s.spindlestream, s.idResolver, s.db, s.config, s.enforcer) 273 return pipes.Router(mw) 274 } 275 276 func (s *State) LabelsRouter(mw *middleware.Middleware) http.Handler { 277 - ls := labels.New(s.oauth, s.pages, s.db, s.validator, s.enforcer) 278 return ls.Router(mw) 279 } 280 281 func (s *State) NotificationsRouter(mw *middleware.Middleware) http.Handler { 282 - notifs := notifications.New(s.db, s.oauth, s.pages) 283 return notifs.Router(mw) 284 } 285 286 func (s *State) SignupRouter() http.Handler { 287 - logger := log.New("signup") 288 - 289 - sig := signup.New(s.config, s.db, s.posthog, s.idResolver, s.pages, logger) 290 return sig.Router() 291 }
··· 205 } 206 207 func (s *State) SpindlesRouter() http.Handler { 208 + logger := log.SubLogger(s.logger, "spindles") 209 210 spindles := &spindles.Spindles{ 211 Db: s.db, ··· 221 } 222 223 func (s *State) KnotsRouter() http.Handler { 224 + logger := log.SubLogger(s.logger, "knots") 225 226 knots := &knots.Knots{ 227 Db: s.db, ··· 238 } 239 240 func (s *State) StringsRouter(mw *middleware.Middleware) http.Handler { 241 + logger := log.SubLogger(s.logger, "strings") 242 243 strs := &avstrings.Strings{ 244 Db: s.db, ··· 253 } 254 255 func (s *State) IssuesRouter(mw *middleware.Middleware) http.Handler { 256 + issues := issues.New( 257 + s.oauth, 258 + s.repoResolver, 259 + s.pages, 260 + s.idResolver, 261 + s.db, 262 + s.config, 263 + s.notifier, 264 + s.validator, 265 + log.SubLogger(s.logger, "issues"), 266 + ) 267 return issues.Router(mw) 268 } 269 270 func (s *State) PullsRouter(mw *middleware.Middleware) http.Handler { 271 + pulls := pulls.New( 272 + s.oauth, 273 + s.repoResolver, 274 + s.pages, 275 + s.idResolver, 276 + s.db, 277 + s.config, 278 + s.notifier, 279 + s.enforcer, 280 + log.SubLogger(s.logger, "pulls"), 281 + ) 282 return pulls.Router(mw) 283 } 284 285 func (s *State) RepoRouter(mw *middleware.Middleware) http.Handler { 286 + repo := repo.New( 287 + s.oauth, 288 + s.repoResolver, 289 + s.pages, 290 + s.spindlestream, 291 + s.idResolver, 292 + s.db, 293 + s.config, 294 + s.notifier, 295 + s.enforcer, 296 + log.SubLogger(s.logger, "repo"), 297 + s.validator, 298 + ) 299 return repo.Router(mw) 300 } 301 302 func (s *State) PipelinesRouter(mw *middleware.Middleware) http.Handler { 303 + pipes := pipelines.New( 304 + s.oauth, 305 + s.repoResolver, 306 + s.pages, 307 + s.spindlestream, 308 + s.idResolver, 309 + s.db, 310 + s.config, 311 + s.enforcer, 312 + log.SubLogger(s.logger, "pipelines"), 313 + ) 314 return pipes.Router(mw) 315 } 316 317 func (s *State) LabelsRouter(mw *middleware.Middleware) http.Handler { 318 + ls := labels.New( 319 + s.oauth, 320 + s.pages, 321 + s.db, 322 + s.validator, 323 + s.enforcer, 324 + log.SubLogger(s.logger, "labels"), 325 + ) 326 return ls.Router(mw) 327 } 328 329 func (s *State) NotificationsRouter(mw *middleware.Middleware) http.Handler { 330 + notifs := notifications.New(s.db, s.oauth, s.pages, log.SubLogger(s.logger, "notifications")) 331 return notifs.Router(mw) 332 } 333 334 func (s *State) SignupRouter() http.Handler { 335 + sig := signup.New(s.config, s.db, s.posthog, s.idResolver, s.pages, log.SubLogger(s.logger, "signup")) 336 return sig.Router() 337 }
+3 -1
appview/state/spindlestream.go
··· 22 ) 23 24 func Spindlestream(ctx context.Context, c *config.Config, d *db.DB, enforcer *rbac.Enforcer) (*ec.Consumer, error) { 25 spindles, err := db.GetSpindles( 26 d, 27 db.FilterIsNot("verified", "null"), ··· 36 srcs[src] = struct{}{} 37 } 38 39 - logger := log.New("spindlestream") 40 cache := cache.New(c.Redis.Addr) 41 cursorStore := cursor.NewRedisCursorStore(cache) 42
··· 22 ) 23 24 func Spindlestream(ctx context.Context, c *config.Config, d *db.DB, enforcer *rbac.Enforcer) (*ec.Consumer, error) { 25 + logger := log.FromContext(ctx) 26 + logger = log.SubLogger(logger, "spindlestream") 27 + 28 spindles, err := db.GetSpindles( 29 d, 30 db.FilterIsNot("verified", "null"), ··· 39 srcs[src] = struct{}{} 40 } 41 42 cache := cache.New(c.Redis.Addr) 43 cursorStore := cursor.NewRedisCursorStore(cache) 44
+15 -19
appview/state/state.go
··· 5 "database/sql" 6 "errors" 7 "fmt" 8 - "log" 9 "log/slog" 10 "net/http" 11 "strings" ··· 13 14 "tangled.org/core/api/tangled" 15 "tangled.org/core/appview" 16 - "tangled.org/core/appview/cache" 17 - "tangled.org/core/appview/cache/session" 18 "tangled.org/core/appview/config" 19 "tangled.org/core/appview/db" 20 "tangled.org/core/appview/models" ··· 29 "tangled.org/core/eventconsumer" 30 "tangled.org/core/idresolver" 31 "tangled.org/core/jetstream" 32 tlog "tangled.org/core/log" 33 "tangled.org/core/rbac" 34 "tangled.org/core/tid" ··· 48 oauth *oauth.OAuth 49 enforcer *rbac.Enforcer 50 pages *pages.Pages 51 - sess *session.SessionStore 52 idResolver *idresolver.Resolver 53 posthog posthog.Client 54 jc *jetstream.JetstreamClient ··· 61 } 62 63 func Make(ctx context.Context, config *config.Config) (*State, error) { 64 - d, err := db.Make(config.Core.DbPath) 65 if err != nil { 66 return nil, fmt.Errorf("failed to create db: %w", err) 67 } ··· 73 74 res, err := idresolver.RedisResolver(config.Redis.ToURL()) 75 if err != nil { 76 - log.Printf("failed to create redis resolver: %v", err) 77 res = idresolver.DefaultResolver() 78 } 79 ··· 82 return nil, fmt.Errorf("failed to create posthog client: %w", err) 83 } 84 85 - pages := pages.NewPages(config, res) 86 - cache := cache.New(config.Redis.Addr) 87 - sess := session.New(cache) 88 - oauth2, err := oauth.New(config, posthog, d, enforcer, res) 89 if err != nil { 90 return nil, fmt.Errorf("failed to start oauth handler: %w", err) 91 } ··· 112 tangled.LabelOpNSID, 113 }, 114 nil, 115 - slog.Default(), 116 wrapper, 117 false, 118 ··· 133 Enforcer: enforcer, 134 IdResolver: res, 135 Config: config, 136 - Logger: tlog.New("ingester"), 137 Validator: validator, 138 } 139 err = jc.StartJetstream(ctx, ingester.Ingest()) ··· 167 state := &State{ 168 d, 169 notifier, 170 - oauth2, 171 enforcer, 172 pages, 173 - sess, 174 res, 175 posthog, 176 jc, ··· 178 repoResolver, 179 knotstream, 180 spindlestream, 181 - slog.Default(), 182 validator, 183 } 184 ··· 277 } 278 timeline, err := db.MakeTimeline(s.db, 50, userDid, filtered) 279 if err != nil { 280 - log.Println(err) 281 s.pages.Notice(w, "timeline", "Uh oh! Failed to load timeline.") 282 } 283 284 repos, err := db.GetTopStarredReposLastWeek(s.db) 285 if err != nil { 286 - log.Println(err) 287 s.pages.Notice(w, "topstarredrepos", "Unable to load.") 288 return 289 } ··· 344 345 timeline, err := db.MakeTimeline(s.db, 5, "", filtered) 346 if err != nil { 347 - log.Println(err) 348 s.pages.Notice(w, "timeline", "Uh oh! Failed to load timeline.") 349 return 350 } 351 352 repos, err := db.GetTopStarredReposLastWeek(s.db) 353 if err != nil { 354 - log.Println(err) 355 s.pages.Notice(w, "topstarredrepos", "Unable to load.") 356 return 357 }
··· 5 "database/sql" 6 "errors" 7 "fmt" 8 "log/slog" 9 "net/http" 10 "strings" ··· 12 13 "tangled.org/core/api/tangled" 14 "tangled.org/core/appview" 15 "tangled.org/core/appview/config" 16 "tangled.org/core/appview/db" 17 "tangled.org/core/appview/models" ··· 26 "tangled.org/core/eventconsumer" 27 "tangled.org/core/idresolver" 28 "tangled.org/core/jetstream" 29 + "tangled.org/core/log" 30 tlog "tangled.org/core/log" 31 "tangled.org/core/rbac" 32 "tangled.org/core/tid" ··· 46 oauth *oauth.OAuth 47 enforcer *rbac.Enforcer 48 pages *pages.Pages 49 idResolver *idresolver.Resolver 50 posthog posthog.Client 51 jc *jetstream.JetstreamClient ··· 58 } 59 60 func Make(ctx context.Context, config *config.Config) (*State, error) { 61 + logger := tlog.FromContext(ctx) 62 + 63 + d, err := db.Make(ctx, config.Core.DbPath) 64 if err != nil { 65 return nil, fmt.Errorf("failed to create db: %w", err) 66 } ··· 72 73 res, err := idresolver.RedisResolver(config.Redis.ToURL()) 74 if err != nil { 75 + logger.Error("failed to create redis resolver", "err", err) 76 res = idresolver.DefaultResolver() 77 } 78 ··· 81 return nil, fmt.Errorf("failed to create posthog client: %w", err) 82 } 83 84 + pages := pages.NewPages(config, res, log.SubLogger(logger, "pages")) 85 + oauth, err := oauth.New(config, posthog, d, enforcer, res) 86 if err != nil { 87 return nil, fmt.Errorf("failed to start oauth handler: %w", err) 88 } ··· 109 tangled.LabelOpNSID, 110 }, 111 nil, 112 + tlog.SubLogger(logger, "jetstream"), 113 wrapper, 114 false, 115 ··· 130 Enforcer: enforcer, 131 IdResolver: res, 132 Config: config, 133 + Logger: log.SubLogger(logger, "ingester"), 134 Validator: validator, 135 } 136 err = jc.StartJetstream(ctx, ingester.Ingest()) ··· 164 state := &State{ 165 d, 166 notifier, 167 + oauth, 168 enforcer, 169 pages, 170 res, 171 posthog, 172 jc, ··· 174 repoResolver, 175 knotstream, 176 spindlestream, 177 + logger, 178 validator, 179 } 180 ··· 273 } 274 timeline, err := db.MakeTimeline(s.db, 50, userDid, filtered) 275 if err != nil { 276 + s.logger.Error("failed to make timeline", "err", err) 277 s.pages.Notice(w, "timeline", "Uh oh! Failed to load timeline.") 278 } 279 280 repos, err := db.GetTopStarredReposLastWeek(s.db) 281 if err != nil { 282 + s.logger.Error("failed to get top starred repos", "err", err) 283 s.pages.Notice(w, "topstarredrepos", "Unable to load.") 284 return 285 } ··· 340 341 timeline, err := db.MakeTimeline(s.db, 5, "", filtered) 342 if err != nil { 343 + s.logger.Error("failed to make timeline", "err", err) 344 s.pages.Notice(w, "timeline", "Uh oh! Failed to load timeline.") 345 return 346 } 347 348 repos, err := db.GetTopStarredReposLastWeek(s.db) 349 if err != nil { 350 + s.logger.Error("failed to get top starred repos", "err", err) 351 s.pages.Notice(w, "topstarredrepos", "Unable to load.") 352 return 353 }
+14 -9
cmd/appview/main.go
··· 2 3 import ( 4 "context" 5 - "log" 6 - "log/slog" 7 "net/http" 8 "os" 9 10 "tangled.org/core/appview/config" 11 "tangled.org/core/appview/state" 12 ) 13 14 func main() { 15 - slog.SetDefault(slog.New(slog.NewTextHandler(os.Stdout, nil))) 16 - 17 ctx := context.Background() 18 19 c, err := config.LoadConfig(ctx) 20 if err != nil { 21 - log.Println("failed to load config", "error", err) 22 return 23 } 24 25 state, err := state.Make(ctx, c) 26 defer func() { 27 - log.Println(state.Close()) 28 }() 29 30 if err != nil { 31 - log.Fatal(err) 32 } 33 34 - log.Println("starting server on", c.Core.ListenAddr) 35 - log.Println(http.ListenAndServe(c.Core.ListenAddr, state.Router())) 36 }
··· 2 3 import ( 4 "context" 5 "net/http" 6 "os" 7 8 "tangled.org/core/appview/config" 9 "tangled.org/core/appview/state" 10 + tlog "tangled.org/core/log" 11 ) 12 13 func main() { 14 ctx := context.Background() 15 + logger := tlog.New("appview") 16 + ctx = tlog.IntoContext(ctx, logger) 17 18 c, err := config.LoadConfig(ctx) 19 if err != nil { 20 + logger.Error("failed to load config", "error", err) 21 return 22 } 23 24 state, err := state.Make(ctx, c) 25 defer func() { 26 + if err := state.Close(); err != nil { 27 + logger.Error("failed to close state", "err", err) 28 + } 29 }() 30 31 if err != nil { 32 + logger.Error("failed to start appview", "err", err) 33 + os.Exit(-1) 34 } 35 36 + logger.Info("starting server", "address", c.Core.ListenAddr) 37 + 38 + if err := http.ListenAndServe(c.Core.ListenAddr, state.Router()); err != nil { 39 + logger.Error("failed to start appview", "err", err) 40 + } 41 }
+9 -3
cmd/spindle/main.go
··· 2 3 import ( 4 "context" 5 "os" 6 7 - "tangled.org/core/log" 8 "tangled.org/core/spindle" 9 _ "tangled.org/core/tid" 10 ) 11 12 func main() { 13 - ctx := log.NewContext(context.Background(), "spindle") 14 err := spindle.Run(ctx) 15 if err != nil { 16 - log.FromContext(ctx).Error("error running spindle", "error", err) 17 os.Exit(-1) 18 } 19 }
··· 2 3 import ( 4 "context" 5 + "log/slog" 6 "os" 7 8 + tlog "tangled.org/core/log" 9 "tangled.org/core/spindle" 10 _ "tangled.org/core/tid" 11 ) 12 13 func main() { 14 + logger := tlog.New("spindl3") 15 + slog.SetDefault(logger) 16 + 17 + ctx := context.Background() 18 + ctx = tlog.IntoContext(ctx, logger) 19 + 20 err := spindle.Run(ctx) 21 if err != nil { 22 + logger.Error("error running spindle", "error", err) 23 os.Exit(-1) 24 } 25 }
+13
go.mod
··· 60 github.com/ProtonMail/go-crypto v1.3.0 // indirect 61 github.com/alecthomas/repr v0.4.0 // indirect 62 github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect 63 github.com/aymerick/douceur v0.2.0 // indirect 64 github.com/beorn7/perks v1.0.1 // indirect 65 github.com/bmatcuk/doublestar/v4 v4.7.1 // indirect 66 github.com/casbin/govaluate v1.3.0 // indirect 67 github.com/cenkalti/backoff/v4 v4.3.0 // indirect 68 github.com/cespare/xxhash/v2 v2.3.0 // indirect 69 github.com/cloudflare/circl v1.6.2-0.20250618153321-aa837fd1539d // indirect 70 github.com/containerd/errdefs v1.0.0 // indirect 71 github.com/containerd/errdefs/pkg v0.3.0 // indirect ··· 84 github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect 85 github.com/go-git/go-billy/v5 v5.6.2 // indirect 86 github.com/go-jose/go-jose/v3 v3.0.4 // indirect 87 github.com/go-logr/logr v1.4.3 // indirect 88 github.com/go-logr/stdr v1.2.2 // indirect 89 github.com/go-redis/cache/v9 v9.0.0 // indirect ··· 126 github.com/lestrrat-go/httprc v1.0.6 // indirect 127 github.com/lestrrat-go/iter v1.0.2 // indirect 128 github.com/lestrrat-go/option v1.0.1 // indirect 129 github.com/mattn/go-isatty v0.0.20 // indirect 130 github.com/minio/sha256-simd v1.0.1 // indirect 131 github.com/mitchellh/mapstructure v1.5.0 // indirect 132 github.com/moby/docker-image-spec v1.3.1 // indirect ··· 134 github.com/moby/term v0.5.2 // indirect 135 github.com/morikuni/aec v1.0.0 // indirect 136 github.com/mr-tron/base58 v1.2.0 // indirect 137 github.com/multiformats/go-base32 v0.1.0 // indirect 138 github.com/multiformats/go-base36 v0.2.0 // indirect 139 github.com/multiformats/go-multibase v0.2.0 // indirect ··· 152 github.com/prometheus/client_model v0.6.2 // indirect 153 github.com/prometheus/common v0.64.0 // indirect 154 github.com/prometheus/procfs v0.16.1 // indirect 155 github.com/ryanuber/go-glob v1.0.0 // indirect 156 github.com/segmentio/asm v1.2.0 // indirect 157 github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect ··· 160 github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect 161 github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect 162 github.com/wyatt915/treeblood v0.1.15 // indirect 163 gitlab.com/staticnoise/goldmark-callout v0.0.0-20240609120641-6366b799e4ab // indirect 164 gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b // indirect 165 gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02 // indirect
··· 60 github.com/ProtonMail/go-crypto v1.3.0 // indirect 61 github.com/alecthomas/repr v0.4.0 // indirect 62 github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect 63 + github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect 64 github.com/aymerick/douceur v0.2.0 // indirect 65 github.com/beorn7/perks v1.0.1 // indirect 66 github.com/bmatcuk/doublestar/v4 v4.7.1 // indirect 67 github.com/casbin/govaluate v1.3.0 // indirect 68 github.com/cenkalti/backoff/v4 v4.3.0 // indirect 69 github.com/cespare/xxhash/v2 v2.3.0 // indirect 70 + github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect 71 + github.com/charmbracelet/lipgloss v1.1.0 // indirect 72 + github.com/charmbracelet/log v0.4.2 // indirect 73 + github.com/charmbracelet/x/ansi v0.8.0 // indirect 74 + github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd // indirect 75 + github.com/charmbracelet/x/term v0.2.1 // indirect 76 github.com/cloudflare/circl v1.6.2-0.20250618153321-aa837fd1539d // indirect 77 github.com/containerd/errdefs v1.0.0 // indirect 78 github.com/containerd/errdefs/pkg v0.3.0 // indirect ··· 91 github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect 92 github.com/go-git/go-billy/v5 v5.6.2 // indirect 93 github.com/go-jose/go-jose/v3 v3.0.4 // indirect 94 + github.com/go-logfmt/logfmt v0.6.0 // indirect 95 github.com/go-logr/logr v1.4.3 // indirect 96 github.com/go-logr/stdr v1.2.2 // indirect 97 github.com/go-redis/cache/v9 v9.0.0 // indirect ··· 134 github.com/lestrrat-go/httprc v1.0.6 // indirect 135 github.com/lestrrat-go/iter v1.0.2 // indirect 136 github.com/lestrrat-go/option v1.0.1 // indirect 137 + github.com/lucasb-eyer/go-colorful v1.2.0 // indirect 138 github.com/mattn/go-isatty v0.0.20 // indirect 139 + github.com/mattn/go-runewidth v0.0.16 // indirect 140 github.com/minio/sha256-simd v1.0.1 // indirect 141 github.com/mitchellh/mapstructure v1.5.0 // indirect 142 github.com/moby/docker-image-spec v1.3.1 // indirect ··· 144 github.com/moby/term v0.5.2 // indirect 145 github.com/morikuni/aec v1.0.0 // indirect 146 github.com/mr-tron/base58 v1.2.0 // indirect 147 + github.com/muesli/termenv v0.16.0 // indirect 148 github.com/multiformats/go-base32 v0.1.0 // indirect 149 github.com/multiformats/go-base36 v0.2.0 // indirect 150 github.com/multiformats/go-multibase v0.2.0 // indirect ··· 163 github.com/prometheus/client_model v0.6.2 // indirect 164 github.com/prometheus/common v0.64.0 // indirect 165 github.com/prometheus/procfs v0.16.1 // indirect 166 + github.com/rivo/uniseg v0.4.7 // indirect 167 github.com/ryanuber/go-glob v1.0.0 // indirect 168 github.com/segmentio/asm v1.2.0 // indirect 169 github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect ··· 172 github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect 173 github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect 174 github.com/wyatt915/treeblood v0.1.15 // indirect 175 + github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect 176 gitlab.com/staticnoise/goldmark-callout v0.0.0-20240609120641-6366b799e4ab // indirect 177 gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b // indirect 178 gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02 // indirect
+27
go.sum
··· 19 github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= 20 github.com/avast/retry-go/v4 v4.6.1 h1:VkOLRubHdisGrHnTu89g08aQEWEgRU7LVEop3GbIcMk= 21 github.com/avast/retry-go/v4 v4.6.1/go.mod h1:V6oF8njAwxJ5gRo1Q7Cxab24xs5NCWZBeaHHBklR8mA= 22 github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= 23 github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= 24 github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= ··· 48 github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 49 github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= 50 github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 51 github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= 52 github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= 53 github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= ··· 120 github.com/go-git/go-git-fixtures/v5 v5.0.0-20241203230421-0753e18f8f03/go.mod h1:hMKrMnUE4W0SJ7bFyM00dyz/HoknZoptGWzrj6M+dEM= 121 github.com/go-jose/go-jose/v3 v3.0.4 h1:Wp5HA7bLQcKnf6YYao/4kpRpVMp/yf6+pJKV8WFSaNY= 122 github.com/go-jose/go-jose/v3 v3.0.4/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= 123 github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= 124 github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= 125 github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= ··· 276 github.com/lestrrat-go/jwx/v2 v2.1.6/go.mod h1:Y722kU5r/8mV7fYDifjug0r8FK8mZdw0K0GpJw/l8pU= 277 github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU= 278 github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= 279 github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= 280 github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= 281 github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= 282 github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 283 github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM= 284 github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= 285 github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk= ··· 300 github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= 301 github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= 302 github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= 303 github.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aGkbLYxPE= 304 github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYgtWibDcT0rExnbI= 305 github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0= ··· 377 github.com/redis/go-redis/v9 v9.7.3/go.mod h1:bGUrSggJ9X9GUmZpZNEOQKaANxSGgOEBRltRTZHSvrA= 378 github.com/resend/resend-go/v2 v2.15.0 h1:B6oMEPf8IEQwn2Ovx/9yymkESLDSeNfLFaNMw+mzHhE= 379 github.com/resend/resend-go/v2 v2.15.0/go.mod h1:3YCb8c8+pLiqhtRFXTyFwlLvfjQtluxOr9HEh2BwCkQ= 380 github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 381 github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= 382 github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= ··· 434 github.com/wyatt915/goldmark-treeblood v0.0.0-20250825231212-5dcbdb2f4b57/go.mod h1:BxSCWByWSRSuembL3cDG1IBUbkBoO/oW/6tF19aA4hs= 435 github.com/wyatt915/treeblood v0.1.15 h1:3KZ3o2LpcKZAzOLqMoW9qeUzKEaKArKpbcPpTkNfQC8= 436 github.com/wyatt915/treeblood v0.1.15/go.mod h1:i7+yhhmzdDP17/97pIsOSffw74EK/xk+qJ0029cSXUY= 437 github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 438 github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 439 github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
··· 19 github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= 20 github.com/avast/retry-go/v4 v4.6.1 h1:VkOLRubHdisGrHnTu89g08aQEWEgRU7LVEop3GbIcMk= 21 github.com/avast/retry-go/v4 v4.6.1/go.mod h1:V6oF8njAwxJ5gRo1Q7Cxab24xs5NCWZBeaHHBklR8mA= 22 + github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= 23 + github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= 24 github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= 25 github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= 26 github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= ··· 50 github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 51 github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= 52 github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 53 + github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc h1:4pZI35227imm7yK2bGPcfpFEmuY1gc2YSTShr4iJBfs= 54 + github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc/go.mod h1:X4/0JoqgTIPSFcRA/P6INZzIuyqdFY5rm8tb41s9okk= 55 + github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY= 56 + github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30= 57 + github.com/charmbracelet/log v0.4.2 h1:hYt8Qj6a8yLnvR+h7MwsJv/XvmBJXiueUcI3cIxsyig= 58 + github.com/charmbracelet/log v0.4.2/go.mod h1:qifHGX/tc7eluv2R6pWIpyHDDrrb/AG71Pf2ysQu5nw= 59 + github.com/charmbracelet/x/ansi v0.8.0 h1:9GTq3xq9caJW8ZrBTe0LIe2fvfLR/bYXKTx2llXn7xE= 60 + github.com/charmbracelet/x/ansi v0.8.0/go.mod h1:wdYl/ONOLHLIVmQaxbIYEC/cRKOQyjTkowiI4blgS9Q= 61 + github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd h1:vy0GVL4jeHEwG5YOXDmi86oYw2yuYUGqz6a8sLwg0X8= 62 + github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs= 63 + github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ= 64 + github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg= 65 github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= 66 github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= 67 github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= ··· 134 github.com/go-git/go-git-fixtures/v5 v5.0.0-20241203230421-0753e18f8f03/go.mod h1:hMKrMnUE4W0SJ7bFyM00dyz/HoknZoptGWzrj6M+dEM= 135 github.com/go-jose/go-jose/v3 v3.0.4 h1:Wp5HA7bLQcKnf6YYao/4kpRpVMp/yf6+pJKV8WFSaNY= 136 github.com/go-jose/go-jose/v3 v3.0.4/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= 137 + github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= 138 + github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= 139 github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= 140 github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= 141 github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= ··· 292 github.com/lestrrat-go/jwx/v2 v2.1.6/go.mod h1:Y722kU5r/8mV7fYDifjug0r8FK8mZdw0K0GpJw/l8pU= 293 github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU= 294 github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= 295 + github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= 296 + github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= 297 github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= 298 github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= 299 github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= 300 github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 301 + github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= 302 + github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= 303 github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM= 304 github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= 305 github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk= ··· 320 github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= 321 github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= 322 github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= 323 + github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc= 324 + github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk= 325 github.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aGkbLYxPE= 326 github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYgtWibDcT0rExnbI= 327 github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0= ··· 399 github.com/redis/go-redis/v9 v9.7.3/go.mod h1:bGUrSggJ9X9GUmZpZNEOQKaANxSGgOEBRltRTZHSvrA= 400 github.com/resend/resend-go/v2 v2.15.0 h1:B6oMEPf8IEQwn2Ovx/9yymkESLDSeNfLFaNMw+mzHhE= 401 github.com/resend/resend-go/v2 v2.15.0/go.mod h1:3YCb8c8+pLiqhtRFXTyFwlLvfjQtluxOr9HEh2BwCkQ= 402 + github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= 403 + github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= 404 + github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= 405 github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 406 github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= 407 github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= ··· 459 github.com/wyatt915/goldmark-treeblood v0.0.0-20250825231212-5dcbdb2f4b57/go.mod h1:BxSCWByWSRSuembL3cDG1IBUbkBoO/oW/6tF19aA4hs= 460 github.com/wyatt915/treeblood v0.1.15 h1:3KZ3o2LpcKZAzOLqMoW9qeUzKEaKArKpbcPpTkNfQC8= 461 github.com/wyatt915/treeblood v0.1.15/go.mod h1:i7+yhhmzdDP17/97pIsOSffw74EK/xk+qJ0029cSXUY= 462 + github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= 463 + github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= 464 github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 465 github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 466 github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
+1 -1
jetstream/jetstream.go
··· 114 115 sched := sequential.NewScheduler(j.ident, logger, j.withDidFilter(processFunc)) 116 117 - client, err := client.NewClient(j.cfg, log.New("jetstream"), sched) 118 if err != nil { 119 return fmt.Errorf("failed to create jetstream client: %w", err) 120 }
··· 114 115 sched := sequential.NewScheduler(j.ident, logger, j.withDidFilter(processFunc)) 116 117 + client, err := client.NewClient(j.cfg, logger, sched) 118 if err != nil { 119 return fmt.Errorf("failed to create jetstream client: %w", err) 120 }
+39
nix/gomod2nix.toml
··· 29 [mod."github.com/avast/retry-go/v4"] 30 version = "v4.6.1" 31 hash = "sha256-PeZc8k4rDV64+k8nZt/oy1YNVbLevltXP3ZD1jf6Z6k=" 32 [mod."github.com/aymerick/douceur"] 33 version = "v0.2.0" 34 hash = "sha256-NiBX8EfOvLXNiK3pJaZX4N73YgfzdrzRXdiBFe3X3sE=" ··· 63 [mod."github.com/cespare/xxhash/v2"] 64 version = "v2.3.0" 65 hash = "sha256-7hRlwSR+fos1kx4VZmJ/7snR7zHh8ZFKX+qqqqGcQpY=" 66 [mod."github.com/cloudflare/circl"] 67 version = "v1.6.2-0.20250618153321-aa837fd1539d" 68 hash = "sha256-0s/i/XmMcuvPQ+qK9OIU5KxwYZyLVXRtdlYvIXRJT3Y=" ··· 145 [mod."github.com/go-jose/go-jose/v3"] 146 version = "v3.0.4" 147 hash = "sha256-RrLHCu9l6k0XVobdZQJ9Sx/VTQcWjrdLR5BEG7yXTEQ=" 148 [mod."github.com/go-logr/logr"] 149 version = "v1.4.3" 150 hash = "sha256-Nnp/dEVNMxLp3RSPDHZzGbI8BkSNuZMX0I0cjWKXXLA=" ··· 298 [mod."github.com/lestrrat-go/option"] 299 version = "v1.0.1" 300 hash = "sha256-jVcIYYVsxElIS/l2akEw32vdEPR8+anR6oeT1FoYULI=" 301 [mod."github.com/mattn/go-isatty"] 302 version = "v0.0.20" 303 hash = "sha256-qhw9hWtU5wnyFyuMbKx+7RB8ckQaFQ8D+8GKPkN3HHQ=" 304 [mod."github.com/mattn/go-sqlite3"] 305 version = "v1.14.24" 306 hash = "sha256-taGKFZFQlR5++5b2oZ1dYS3RERKv6yh1gniNWhb4egg=" ··· 328 [mod."github.com/mr-tron/base58"] 329 version = "v1.2.0" 330 hash = "sha256-8FzMu3kHUbBX10pUdtGf59Ag7BNupx8ZHeUaodR1/Vk=" 331 [mod."github.com/multiformats/go-base32"] 332 version = "v0.1.0" 333 hash = "sha256-O2IM7FB+Y9MkDdZztyQL5F8oEnmON2Yew7XkotQziio=" ··· 394 [mod."github.com/resend/resend-go/v2"] 395 version = "v2.15.0" 396 hash = "sha256-1lMoxuMLQXaNWFKadS6rpztAKwvIl3/LWMXqw7f5WYg=" 397 [mod."github.com/ryanuber/go-glob"] 398 version = "v1.0.0" 399 hash = "sha256-YkMl1utwUhi3E0sHK23ISpAsPyj4+KeXyXKoFYGXGVY=" ··· 440 [mod."github.com/wyatt915/treeblood"] 441 version = "v0.1.15" 442 hash = "sha256-hb99exdkoY2Qv8WdDxhwgPXGbEYimUr6wFtPXEvcO9g=" 443 [mod."github.com/yuin/goldmark"] 444 version = "v1.7.13" 445 hash = "sha256-vBCxZrPYPc8x/nvAAv3Au59dCCyfS80Vw3/a9EXK7TE="
··· 29 [mod."github.com/avast/retry-go/v4"] 30 version = "v4.6.1" 31 hash = "sha256-PeZc8k4rDV64+k8nZt/oy1YNVbLevltXP3ZD1jf6Z6k=" 32 + [mod."github.com/aymanbagabas/go-osc52/v2"] 33 + version = "v2.0.1" 34 + hash = "sha256-6Bp0jBZ6npvsYcKZGHHIUSVSTAMEyieweAX2YAKDjjg=" 35 [mod."github.com/aymerick/douceur"] 36 version = "v0.2.0" 37 hash = "sha256-NiBX8EfOvLXNiK3pJaZX4N73YgfzdrzRXdiBFe3X3sE=" ··· 66 [mod."github.com/cespare/xxhash/v2"] 67 version = "v2.3.0" 68 hash = "sha256-7hRlwSR+fos1kx4VZmJ/7snR7zHh8ZFKX+qqqqGcQpY=" 69 + [mod."github.com/charmbracelet/colorprofile"] 70 + version = "v0.2.3-0.20250311203215-f60798e515dc" 71 + hash = "sha256-D9E/bMOyLXAUVOHA1/6o3i+vVmLfwIMOWib6sU7A6+Q=" 72 + [mod."github.com/charmbracelet/lipgloss"] 73 + version = "v1.1.0" 74 + hash = "sha256-RHsRT2EZ1nDOElxAK+6/DC9XAaGVjDTgPvRh3pyCfY4=" 75 + [mod."github.com/charmbracelet/log"] 76 + version = "v0.4.2" 77 + hash = "sha256-3w1PCM/c4JvVEh2d0sMfv4C77Xs1bPa1Ea84zdynC7I=" 78 + [mod."github.com/charmbracelet/x/ansi"] 79 + version = "v0.8.0" 80 + hash = "sha256-/YyDkGrULV2BtnNk3ojeSl0nUWQwIfIdW7WJuGbAZas=" 81 + [mod."github.com/charmbracelet/x/cellbuf"] 82 + version = "v0.0.13-0.20250311204145-2c3ea96c31dd" 83 + hash = "sha256-XAhCOt8qJ2vR77lH1ez0IVU1/2CaLTq9jSmrHVg5HHU=" 84 + [mod."github.com/charmbracelet/x/term"] 85 + version = "v0.2.1" 86 + hash = "sha256-VBkCZLI90PhMasftGw3403IqoV7d3E5WEGAIVrN5xQM=" 87 [mod."github.com/cloudflare/circl"] 88 version = "v1.6.2-0.20250618153321-aa837fd1539d" 89 hash = "sha256-0s/i/XmMcuvPQ+qK9OIU5KxwYZyLVXRtdlYvIXRJT3Y=" ··· 166 [mod."github.com/go-jose/go-jose/v3"] 167 version = "v3.0.4" 168 hash = "sha256-RrLHCu9l6k0XVobdZQJ9Sx/VTQcWjrdLR5BEG7yXTEQ=" 169 + [mod."github.com/go-logfmt/logfmt"] 170 + version = "v0.6.0" 171 + hash = "sha256-RtIG2qARd5sT10WQ7F3LR8YJhS8exs+KiuUiVf75bWg=" 172 [mod."github.com/go-logr/logr"] 173 version = "v1.4.3" 174 hash = "sha256-Nnp/dEVNMxLp3RSPDHZzGbI8BkSNuZMX0I0cjWKXXLA=" ··· 322 [mod."github.com/lestrrat-go/option"] 323 version = "v1.0.1" 324 hash = "sha256-jVcIYYVsxElIS/l2akEw32vdEPR8+anR6oeT1FoYULI=" 325 + [mod."github.com/lucasb-eyer/go-colorful"] 326 + version = "v1.2.0" 327 + hash = "sha256-Gg9dDJFCTaHrKHRR1SrJgZ8fWieJkybljybkI9x0gyE=" 328 [mod."github.com/mattn/go-isatty"] 329 version = "v0.0.20" 330 hash = "sha256-qhw9hWtU5wnyFyuMbKx+7RB8ckQaFQ8D+8GKPkN3HHQ=" 331 + [mod."github.com/mattn/go-runewidth"] 332 + version = "v0.0.16" 333 + hash = "sha256-NC+ntvwIpqDNmXb7aixcg09il80ygq6JAnW0Gb5b/DQ=" 334 [mod."github.com/mattn/go-sqlite3"] 335 version = "v1.14.24" 336 hash = "sha256-taGKFZFQlR5++5b2oZ1dYS3RERKv6yh1gniNWhb4egg=" ··· 358 [mod."github.com/mr-tron/base58"] 359 version = "v1.2.0" 360 hash = "sha256-8FzMu3kHUbBX10pUdtGf59Ag7BNupx8ZHeUaodR1/Vk=" 361 + [mod."github.com/muesli/termenv"] 362 + version = "v0.16.0" 363 + hash = "sha256-hGo275DJlyLtcifSLpWnk8jardOksdeX9lH4lBeE3gI=" 364 [mod."github.com/multiformats/go-base32"] 365 version = "v0.1.0" 366 hash = "sha256-O2IM7FB+Y9MkDdZztyQL5F8oEnmON2Yew7XkotQziio=" ··· 427 [mod."github.com/resend/resend-go/v2"] 428 version = "v2.15.0" 429 hash = "sha256-1lMoxuMLQXaNWFKadS6rpztAKwvIl3/LWMXqw7f5WYg=" 430 + [mod."github.com/rivo/uniseg"] 431 + version = "v0.4.7" 432 + hash = "sha256-rDcdNYH6ZD8KouyyiZCUEy8JrjOQoAkxHBhugrfHjFo=" 433 [mod."github.com/ryanuber/go-glob"] 434 version = "v1.0.0" 435 hash = "sha256-YkMl1utwUhi3E0sHK23ISpAsPyj4+KeXyXKoFYGXGVY=" ··· 476 [mod."github.com/wyatt915/treeblood"] 477 version = "v0.1.15" 478 hash = "sha256-hb99exdkoY2Qv8WdDxhwgPXGbEYimUr6wFtPXEvcO9g=" 479 + [mod."github.com/xo/terminfo"] 480 + version = "v0.0.0-20220910002029-abceb7e1c41e" 481 + hash = "sha256-GyCDxxMQhXA3Pi/TsWXpA8cX5akEoZV7CFx4RO3rARU=" 482 [mod."github.com/yuin/goldmark"] 483 version = "v1.7.13" 484 hash = "sha256-vBCxZrPYPc8x/nvAAv3Au59dCCyfS80Vw3/a9EXK7TE="
+5 -4
xrpc/serviceauth/service_auth.go
··· 9 10 "github.com/bluesky-social/indigo/atproto/auth" 11 "tangled.org/core/idresolver" 12 xrpcerr "tangled.org/core/xrpc/errors" 13 ) 14 ··· 22 23 func NewServiceAuth(logger *slog.Logger, resolver *idresolver.Resolver, audienceDid string) *ServiceAuth { 24 return &ServiceAuth{ 25 - logger: logger, 26 resolver: resolver, 27 audienceDid: audienceDid, 28 } ··· 30 31 func (sa *ServiceAuth) VerifyServiceAuth(next http.Handler) http.Handler { 32 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 33 - l := sa.logger.With("url", r.URL) 34 - 35 token := r.Header.Get("Authorization") 36 token = strings.TrimPrefix(token, "Bearer ") 37 ··· 42 43 did, err := s.Validate(r.Context(), token, nil) 44 if err != nil { 45 - l.Error("signature verification failed", "err", err) 46 writeError(w, xrpcerr.AuthError(err), http.StatusForbidden) 47 return 48 } 49 50 r = r.WithContext( 51 context.WithValue(r.Context(), ActorDid, did),
··· 9 10 "github.com/bluesky-social/indigo/atproto/auth" 11 "tangled.org/core/idresolver" 12 + "tangled.org/core/log" 13 xrpcerr "tangled.org/core/xrpc/errors" 14 ) 15 ··· 23 24 func NewServiceAuth(logger *slog.Logger, resolver *idresolver.Resolver, audienceDid string) *ServiceAuth { 25 return &ServiceAuth{ 26 + logger: log.SubLogger(logger, "serviceauth"), 27 resolver: resolver, 28 audienceDid: audienceDid, 29 } ··· 31 32 func (sa *ServiceAuth) VerifyServiceAuth(next http.Handler) http.Handler { 33 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 34 token := r.Header.Get("Authorization") 35 token = strings.TrimPrefix(token, "Bearer ") 36 ··· 41 42 did, err := s.Validate(r.Context(), token, nil) 43 if err != nil { 44 + sa.logger.Error("signature verification failed", "err", err) 45 writeError(w, xrpcerr.AuthError(err), http.StatusForbidden) 46 return 47 } 48 + 49 + sa.logger.Debug("valid signature", ActorDid, did) 50 51 r = r.WithContext( 52 context.WithValue(r.Context(), ActorDid, did),