commit bdf7ef6f884f541cbc9915752a2667570b3572c5 from: Stefan Sperling via: Thomas Adam date: Mon Apr 29 12:23:45 2024 UTC expose authenticated gotd user account in HTTP notifications ok op@ commit - a6cc387fec23bd4635f8b81cc025832da261d1ef commit + bdf7ef6f884f541cbc9915752a2667570b3572c5 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 - 8dc1ab0bddd3bfd0e0ec2e9de7cf1a1e6f77c065 blob + 973cfb429fc7bf147d1a19a10f8bff1eac125ea1 --- gotd/gotd.h +++ gotd/gotd.h @@ -480,6 +480,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 enter_chroot(const char *); blob - 8f5c7c4ec82547aac85eaa8e00be8b760ce44a99 blob + 7fae44225c920ee600411e33b08a85e7f1f7d186 --- gotd/libexec/got-notify-http/got-notify-http.c +++ gotd/libexec/got-notify-http/got-notify-http.c @@ -48,7 +48,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); } @@ -202,7 +202,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; @@ -222,6 +222,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); @@ -230,7 +232,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; @@ -254,6 +256,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); @@ -264,7 +268,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; @@ -293,6 +298,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) { @@ -559,7 +566,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; @@ -582,6 +590,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) { @@ -690,7 +700,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; @@ -710,25 +720,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; } @@ -845,6 +856,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; @@ -860,7 +872,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; @@ -874,6 +886,9 @@ main(int argc, char **argv) case 'r': repo = optarg; break; + case 'u': + gotd_auth_user = optarg; + break; default: usage(); } @@ -911,7 +926,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 - 1c7df38d54eae629cb515f41861efe1173fd9c2c blob + e0fc6e235bf2dc7339ededb292d026715f715456 --- gotd/notify.c +++ gotd/notify.c @@ -259,9 +259,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; @@ -274,6 +275,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; @@ -292,12 +295,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) @@ -307,18 +313,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; } } @@ -330,6 +341,7 @@ send_notification(struct imsg *imsg, struct gotd_imsge } done: close(fd); + free(username); return err; } blob - 8ad66ce4e9eba86b097805070aa8ddaf5789860c blob + 946a1a9daf14abccfa57afc447900e83866d270e --- 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",