commit d36998aec867c8134466eccfe048dc8671eecca5 from: Stefan Sperling date: Mon Apr 29 11:54:13 2024 UTC expose authenticated gotd user account in HTTP notifications ok op@ commit - b2c9f618aa4d760f0edfc7dbf6bcd01ca38aca17 commit + d36998aec867c8134466eccfe048dc8671eecca5 blob - c23b8863b3184121b8c368dd247b965685f04711 blob + 3dea3bfa8e197050bf539168af1366e3871504f4 --- gotd/gotd.conf.5 +++ gotd/gotd.conf.5 @@ -380,6 +380,10 @@ When several commits are batched in a single send oper the fields are available for each commit object. .It Dv repo The repository name as string. +.It Dv auth_user +The committer's user account as authenticated by +.Xr gotd 8 +as a string. .It Dv id The commit ID as string, may be abbreviated. .It Dv committer @@ -448,6 +452,10 @@ to be set: .Bl -tag -compact -width Ds .It Dv repo The repository name as string. +.It Dv auth_user +The committer's user account as authenticated by +.Xr gotd 8 +as a string. .It Dv ref The removed branch reference. .It Dv id @@ -458,6 +466,10 @@ The tag notification has the following fields, all gua .Bl -tag -width Ds .It repo The repository name as string. +.It Dv auth_user +The committer's user account as authenticated by +.Xr gotd 8 +as a string. .It tag The tag reference. .It tagger blob - c4375525ccc474f8fe090e2653580512c0faf220 blob + 02ec51dafe5e458386554dc03f1fad6aa05c0026 --- gotd/gotd.h +++ gotd/gotd.h @@ -477,6 +477,8 @@ struct gotd_imsg_notification_content { struct gotd_imsg_notify { char repo_name[NAME_MAX]; char subject_line[64]; + size_t username_len; + /* Followed by username_len data bytes. */ }; int parse_config(const char *, enum gotd_procid, struct gotd *); blob - 4ee2c0b6e836e4cf92abff873a5b9c94c9da2a21 blob + 110aa3179a27bd4af209fd577262ccccdd94f82b --- gotd/libexec/got-notify-http/got-notify-http.c +++ gotd/libexec/got-notify-http/got-notify-http.c @@ -46,7 +46,7 @@ static int http_timeout = 300; /* 5 minutes in secon __dead static void usage(void) { - fprintf(stderr, "usage: %s [-c] -r repo -h host -p port path\n", + fprintf(stderr, "usage: %s [-c] -r repo -h host -p port -u user path\n", getprogname()); exit(1); } @@ -200,7 +200,7 @@ json_author(FILE *fp, const char *type, char *address, } static int -jsonify_branch_rm(FILE *fp, char *line, const char *repo) +jsonify_branch_rm(FILE *fp, char *line, const char *repo, const char *user) { char *ref, *id; @@ -220,6 +220,8 @@ jsonify_branch_rm(FILE *fp, char *line, const char *re fputc('{', fp); json_field(fp, "type", "branch-deleted", 1); json_field(fp, "repo", repo, 1); + if (user) + json_field(fp, "auth_user", user, 1); json_field(fp, "ref", ref, 1); json_field(fp, "id", id, 0); fputc('}', fp); @@ -228,7 +230,7 @@ jsonify_branch_rm(FILE *fp, char *line, const char *re } static int -jsonify_commit_short(FILE *fp, char *line, const char *repo) +jsonify_commit_short(FILE *fp, char *line, const char *repo, const char *user) { char *t, *date, *id, *author, *message; @@ -252,6 +254,8 @@ jsonify_commit_short(FILE *fp, char *line, const char fprintf(fp, "{\"type\":\"commit\",\"short\":true,"); json_field(fp, "repo", repo, 1); + if (user) + json_field(fp, "auth_user", user, 1); json_field(fp, "id", id, 1); json_author(fp, "committer", author, 1); json_date(fp, "date", date, 1); @@ -262,7 +266,8 @@ jsonify_commit_short(FILE *fp, char *line, const char } static int -jsonify_commit(FILE *fp, const char *repo, char **line, ssize_t *linesize) +jsonify_commit(FILE *fp, const char *repo, const char *user, + char **line, ssize_t *linesize) { const char *errstr; char *author = NULL; @@ -291,6 +296,8 @@ jsonify_commit(FILE *fp, const char *repo, char **line fprintf(fp, "{\"type\":\"commit\",\"short\":false,"); json_field(fp, "repo", repo, 1); + if (user) + json_field(fp, "auth_user", user, 1); json_field(fp, "id", l, 1); while (!done) { @@ -557,7 +564,8 @@ jsonify_commit(FILE *fp, const char *repo, char **line } static int -jsonify_tag(FILE *fp, const char *repo, char **line, ssize_t *linesize) +jsonify_tag(FILE *fp, const char *repo, const char *user, + char **line, ssize_t *linesize) { const char *errstr; char *l; @@ -580,6 +588,8 @@ jsonify_tag(FILE *fp, const char *repo, char **line, s fputc('{', fp); json_field(fp, "type", "tag", 1); json_field(fp, "repo", repo, 1); + if (user) + json_field(fp, "auth_user", user, 1); json_field(fp, "tag", l, 1); while (!done) { @@ -688,7 +698,7 @@ jsonify_tag(FILE *fp, const char *repo, char **line, s } static int -jsonify(FILE *fp, const char *repo) +jsonify(FILE *fp, const char *repo, const char *user) { char *line = NULL; size_t linesize = 0; @@ -708,25 +718,26 @@ jsonify(FILE *fp, const char *repo) needcomma = 1; if (strncmp(line, "Removed refs/heads/", 19) == 0) { - if (jsonify_branch_rm(fp, line, repo) == -1) + if (jsonify_branch_rm(fp, line, repo, user) == -1) fatal("jsonify_branch_rm"); continue; } if (strncmp(line, "commit ", 7) == 0) { - if (jsonify_commit(fp, repo, &line, &linesize) == -1) + if (jsonify_commit(fp, repo, user, + &line, &linesize) == -1) fatal("jsonify_commit"); continue; } if (*line >= '0' && *line <= '9') { - if (jsonify_commit_short(fp, line, repo) == -1) + if (jsonify_commit_short(fp, line, repo, user) == -1) fatal("jsonify_commit_short"); continue; } if (strncmp(line, "tag ", 4) == 0) { - if (jsonify_tag(fp, repo, &line, &linesize) == -1) + if (jsonify_tag(fp, repo, user, &line, &linesize) == -1) fatal("jsonify_tag"); continue; } @@ -843,6 +854,7 @@ main(int argc, char **argv) const char *errstr; const char *repo = NULL; const char *host = NULL, *port = NULL, *path = NULL; + const char *gotd_auth_user = NULL; char *auth, *line, *spc; size_t len; ssize_t r; @@ -858,7 +870,7 @@ main(int argc, char **argv) log_init(0, LOG_DAEMON); - while ((ch = getopt(argc, argv, "ch:p:r:")) != -1) { + while ((ch = getopt(argc, argv, "ch:p:r:u:")) != -1) { switch (ch) { case 'c': tls = 1; @@ -872,6 +884,9 @@ main(int argc, char **argv) case 'r': repo = optarg; break; + case 'u': + gotd_auth_user = optarg; + break; default: usage(); } @@ -909,7 +924,7 @@ main(int argc, char **argv) if (tmpfp == NULL) fatal("opentemp"); - jsonify(tmpfp, repo); + jsonify(tmpfp, repo, gotd_auth_user); paylen = ftello(tmpfp); if (paylen == -1) blob - cc0b17db44d592bb3d0b20f73b44556cac260e9c blob + 936d588b3f5a49ce4f818a58d0f599adf5ddc0b9 --- gotd/notify.c +++ gotd/notify.c @@ -261,9 +261,10 @@ notify_email(struct gotd_notification_target *target, } static void -notify_http(struct gotd_notification_target *target, const char *repo, int fd) +notify_http(struct gotd_notification_target *target, const char *repo, + const char *username, int fd) { - const char *argv[10]; + const char *argv[12]; int argc = 0; argv[argc++] = GOTD_PATH_PROG_NOTIFY_HTTP; @@ -276,6 +277,8 @@ notify_http(struct gotd_notification_target *target, c argv[argc++] = target->conf.http.hostname; argv[argc++] = "-p"; argv[argc++] = target->conf.http.port; + argv[argc++] = "-u"; + argv[argc++] = username; argv[argc++] = target->conf.http.path; @@ -294,12 +297,15 @@ send_notification(struct imsg *imsg, struct gotd_imsge struct gotd_repo *repo; struct gotd_notification_target *target; int fd; + char *username = NULL; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; - if (datalen != sizeof(inotify)) + if (datalen < sizeof(inotify)) return got_error(GOT_ERR_PRIVSEP_LEN); - memcpy(&inotify, imsg->data, datalen); + memcpy(&inotify, imsg->data, sizeof(inotify)); + if (datalen != sizeof(inotify) + inotify.username_len) + return got_error(GOT_ERR_PRIVSEP_LEN); repo = gotd_find_repo_by_name(inotify.repo_name, gotd_notify.repos); if (repo == NULL) @@ -309,18 +315,23 @@ send_notification(struct imsg *imsg, struct gotd_imsge if (fd == -1) return got_error(GOT_ERR_PRIVSEP_NO_FD); + username = strndup(imsg->data + sizeof(inotify), inotify.username_len); + if (username == NULL) + return got_error_from_errno("strndup"); + if (lseek(fd, 0, SEEK_SET) == -1) { err = got_error_from_errno("lseek"); goto done; } + STAILQ_FOREACH(target, &repo->notification_targets, entry) { switch (target->type) { case GOTD_NOTIFICATION_VIA_EMAIL: notify_email(target, inotify.subject_line, fd); break; case GOTD_NOTIFICATION_VIA_HTTP: - notify_http(target, repo->name, fd); + notify_http(target, repo->name, username, fd); break; } } @@ -332,6 +343,7 @@ send_notification(struct imsg *imsg, struct gotd_imsge } done: close(fd); + free(username); return err; } blob - 1d073e97037a9cb64129ca446a58b0f3fe2a2a62 blob + d957c78baa66812aad479f8135c63971e8397e2e --- gotd/session_write.c +++ gotd/session_write.c @@ -497,6 +497,7 @@ forward_notification(struct gotd_session_client *clien size_t datalen; struct gotd_imsg_notify inotify; const char *action; + struct ibuf *wbuf; memset(&inotify, 0, sizeof(inotify)); @@ -566,13 +567,28 @@ forward_notification(struct gotd_session_client *clien "%s: %s %s %s", gotd_session.repo_cfg->name, client->username, action, notif->refname); - if (gotd_imsg_compose_event(iev, GOTD_IMSG_NOTIFY, - PROC_SESSION_WRITE, notif->fd, &inotify, sizeof(inotify)) - == -1) { - err = got_error_from_errno("imsg compose NOTIFY"); + inotify.username_len = strlen(client->username); + wbuf = imsg_create(&iev->ibuf, GOTD_IMSG_NOTIFY, + PROC_SESSION_WRITE, gotd_session.pid, + sizeof(inotify) + inotify.username_len); + if (wbuf == NULL) { + err = got_error_from_errno("imsg_create NOTIFY"); + goto done; + } + if (imsg_add(wbuf, &inotify, sizeof(inotify)) == -1) { + err = got_error_from_errno("imsg_add NOTIFY"); goto done; } + if (imsg_add(wbuf, client->username, inotify.username_len) == -1) { + err = got_error_from_errno("imsg_add NOTIFY"); + goto done; + } + + ibuf_fd_set(wbuf, notif->fd); notif->fd = -1; + + imsg_close(&iev->ibuf, wbuf); + gotd_imsg_event_add(iev); done: if (notif->fd != -1) close(notif->fd); blob - 23a8d91f145b36a4fca7522f147af43bd6c98956 blob + 33fbf586ff94a94ca7f4a10f06a3814106db946d --- regress/gotd/http_notification.sh +++ regress/gotd/http_notification.sh @@ -64,6 +64,7 @@ test_file_changed() { "type":"commit", "short":false, "repo":"test-repo", + "auth_user":"${GOTD_DEVUSER}", "id":"$commit_id", "author":{ "full":"$GOT_AUTHOR", @@ -155,6 +156,7 @@ test_bad_utf8() { "type":"commit", "short":false, "repo":"test-repo", + "auth_user":"${GOTD_DEVUSER}", "id":"$commit_id", "author":{ "full":"$GOT_AUTHOR", @@ -255,6 +257,7 @@ test_many_commits_not_summarized() { "type":"commit", "short":false, "repo":"test-repo", + "auth_user":"${GOTD_DEVUSER}", "id":"$commit_id", "author":{ "full":"$GOT_AUTHOR", @@ -359,6 +362,7 @@ test_many_commits_summarized() { "type":"commit", "short":true, "repo":"test-repo", + "auth_user":"${GOTD_DEVUSER}", "id":"$commit_id", "committer":{ "user":"$GOT_AUTHOR_8" @@ -439,6 +443,7 @@ test_branch_created() { "type":"commit", "short":false, "repo":"test-repo", + "auth_user":"${GOTD_DEVUSER}", "id":"$commit_id", "author":{ "full":"$GOT_AUTHOR", @@ -517,6 +522,7 @@ test_branch_removed() { {"notifications":[{ "type":"branch-deleted", "repo":"test-repo", + "auth_user":"${GOTD_DEVUSER}", "ref":"refs/heads/newbranch", "id":"$commit_id" }]} @@ -570,6 +576,7 @@ test_tag_created() { {"notifications":[{ "type":"tag", "repo":"test-repo", + "auth_user":"${GOTD_DEVUSER}", "tag":"refs/tags/1.0", "tagger":{ "full":"$GOT_AUTHOR", @@ -649,6 +656,7 @@ test_tag_changed() { {"notifications":[{ "type":"tag", "repo":"test-repo", + "auth_user":"${GOTD_DEVUSER}", "tag":"refs/tags/1.0", "tagger":{ "full":"$GOT_AUTHOR",