Skip to content

Commit c78800b

Browse files
committed
WIP
1 parent 6c48b18 commit c78800b

File tree

3 files changed

+85
-46
lines changed

3 files changed

+85
-46
lines changed

.github/workflows/runner.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ jobs:
2323

2424
- uses: ./
2525
with:
26-
# packit-url: https://packit.dide.ic.ac.uk/reside
26+
packit-url: https://packit.dide.ic.ac.uk/reside
2727
reports: |
2828
- name: "incoming_data"
2929
- name: "explicit"

action.yaml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
11
name: 'orderly'
22
description: 'Action to run an orderly workflow on Packit.'
33
inputs:
4+
packit-url:
5+
description: "URL of a packit instance to be configured as a remote location"
6+
required: false
47
reports:
58
type: 'string'
69
description: 'List of reports to run'
10+
default: "[]"
711

812
runs:
913
using: "composite"
1014
steps:
1115
- shell: bash
1216
run:
13-
echo ${{ inputs.reports }}
17+
data=$(mktemp)
18+
echo '${{ inputs.reports }}' > $data
19+
Rscript --verbose '${{ github.action_path }}/run.R' '${{ inputs.packit-url }}' "$run"

run.R

Lines changed: 77 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,34 @@
1-
PACKIT_URL <- "https://packit.dide.ic.ac.uk/reside"
2-
3-
get_packit_audience <- function(base_url) {
4-
response <- httr2::request(base_url) |>
1+
get_packit_audience <- function(url) {
2+
response <- httr2::request(url) |>
53
httr2::req_url_path_append("packit/api/auth/login/service/audience") |>
64
httr2::req_perform() |>
75
httr2::resp_body_json()
86
response$audience
97
}
108

9+
check_audience <- function(url) {
10+
# The server will match its configured audience against the one found in the
11+
# token exactly. A mismatch could occur if, for example, the user provided a
12+
# non-canonical URL that routes to the same place but isn't strictly equal
13+
# (eg. using `https://hostname:443` instead of just `https://hostname`).
14+
#
15+
# It is tempting to just use the audience provided by the server instead of
16+
# PACKIT_URL and not have to worry about it ever failing to match. If we did
17+
# that though, a malicious server could present an arbitrary audience and use
18+
# the token we give it to login to a completely different service on behalf on
19+
# this action, and we do not want to allow that.
20+
#
21+
# This warning provides an easy diagnostic and resolution path for the benign
22+
# case of a non-canonical URL, while avoiding the aforementioned pitfall.
23+
expected_audience <- get_packit_audience(url)
24+
if (expected_audience != url) {
25+
cli::cli_warn(
26+
paste("The Packit URL is {.url {url}}, but the server is expecting",
27+
"the audience to be {.url {expected_audience}}. Authentication is",
28+
"likely to fail."))
29+
}
30+
}
31+
1132
get_oidc_token <- function(audience) {
1233
url <- Sys.getenv("ACTIONS_ID_TOKEN_REQUEST_URL", NA)
1334
token <- Sys.getenv("ACTIONS_ID_TOKEN_REQUEST_TOKEN", NA)
@@ -26,19 +47,28 @@ get_oidc_token <- function(audience) {
2647
response$value
2748
}
2849

29-
get_packit_token <- function(base_url, token) {
30-
response <- httr2::request(base_url) |>
50+
get_packit_token_service <- function(url, token) {
51+
response <- httr2::request(url) |>
3152
httr2::req_url_path_append("packit/api/auth/login/service") |>
3253
httr2::req_body_json(list(token = token)) |>
3354
httr2::req_perform() |>
3455
httr2::resp_body_json()
3556
response$token
3657
}
3758

38-
task_run <- function(branch, hash, name) {
39-
req <- httr2::request(PACKIT_URL) |>
59+
get_packit_token_api <- function(url, token) {
60+
response <- httr2::request(url) |>
61+
httr2::req_url_path_append("packit/api/auth/login/api") |>
62+
httr2::req_body_json(list(token = token)) |>
63+
httr2::req_perform() |>
64+
httr2::resp_body_json()
65+
response$token
66+
}
67+
68+
task_run <- function(url, token, branch, hash, name) {
69+
req <- httr2::request(url) |>
4070
httr2::req_url_path_append("packit/api/runner/run") |>
41-
httr2::req_auth_bearer_token(packit_token) |>
71+
httr2::req_auth_bearer_token(token) |>
4272
httr2::req_body_json(list(name = name, branch = branch, hash = hash))
4373

4474
task <- httr2::req_perform(req) |>
@@ -47,59 +77,62 @@ task_run <- function(branch, hash, name) {
4777
task$taskId
4878
}
4979

50-
task_status <- function(task_id, include_logs = FALSE) {
51-
req <- httr2::request(PACKIT_URL) |>
52-
httr2::req_auth_bearer_token(packit_token) |>
80+
task_status <- function(url, token, task_id, include_logs = FALSE) {
81+
req <- httr2::request(url) |>
82+
httr2::req_auth_bearer_token(token) |>
5383
httr2::req_url_path_append("packit/api/runner/status", task_id) |>
5484
httr2::req_url_query(includeLogs = include_logs)
5585

5686
httr2::req_perform(req) |>
5787
httr2::resp_body_json()
5888
}
5989

60-
task_wait <- function(task_id) {
90+
task_wait <- function(url, token, task_id) {
6191
while (TRUE) {
62-
status <- task_status(task_id)
92+
status <- task_status(url, token, task_id)
6393
if (status$status != "RUNNING") {
6494
return (invisible(status))
6595
}
6696
Sys.sleep(1)
6797
}
6898
}
6999

70-
# The server will match its configured audience against the one found in the
71-
# token exactly. A mismatch could occur if, for example, the user provided a
72-
# non-canonical URL that routes to the same place but isn't strictly equal
73-
# (eg. using `https://hostname:443` instead of just `https://hostname`).
74-
#
75-
# It is tempting to just use the audience provided by the server instead of
76-
# PACKIT_URL and not have to worry about it ever failing to match. If we did
77-
# that though, a malicious server could present an arbitrary audience and use
78-
# the token we give it to login to a completely different service on behalf on
79-
# this action, and we do not want to allow that.
80-
#
81-
# This warning provides an easy diagnostic and resolution path for the benign
82-
# case of a non-canonical URL, while avoiding the aforementioned pitfall.
83-
expected_audience <- get_packit_audience(PACKIT_URL)
84-
if (expected_audience != PACKIT_URL) {
85-
cli::cli_warn(
86-
paste("The Packit URL is {.url {PACKIT_URL}}, but the server is expecting",
87-
"the audience to be {.url {expected_audience}}. Authentication is",
88-
"likely to fail."))
100+
authenticate <- function(url) {
101+
packit_token <- Sys.getenv("PACKIT_TOKEN", NA)
102+
if (!is.na(packit_token)) {
103+
return (packit_token)
104+
}
105+
106+
github_token <- Sys.getenv("GITHUB_TOKEN", NA)
107+
if (!is.na(github_token)) {
108+
return(get_packit_token_api(url, github_token))
109+
}
110+
111+
check_audience(url)
112+
github_token <- get_oidc_token(url)
113+
get_packit_token_service(url, github_token)
89114
}
90115

91-
github_token <- get_oidc_token(PACKIT_URL)
92-
packit_token <- get_packit_token(PACKIT_URL, github_token)
116+
main <- function(args = commandArgs(trailingOnly = TRUE)) {
117+
url <- args[[1]]
118+
input <- args[[2]]
119+
120+
ref_name <- Sys.getenv("GITHUB_REF_NAME", "main")
121+
sha <- Sys.getenv("GITHUB_SHA", "HEAD")
93122

94-
ref_name <- Sys.getenv("GITHUB_REF_NAME", "main")
95-
sha <- Sys.getenv("GITHUB_SHA", "HEAD")
96-
name <- "incoming_data"
123+
token <- authenticate(url)
124+
data <- yaml::read_yaml(file = input)
97125

98-
task_id <- task_run(ref_name, sha, name)
99-
task_wait(task_id)
100-
status <- task_status(task_id)
101-
writeLines(unlist(status$logs))
126+
for (entry in data) {
127+
task_id <- task_run(url, token, ref_name, sha, entry$name)
128+
task_wait(url, token, task_id)
129+
status <- task_status(url, token, task_id, include_logs = TRUE)
130+
writeLines(unlist(status$logs))
102131

103-
if (status$status != "COMPLETE") {
104-
cli::cli_abort("Task failed")
132+
if (status$status != "COMPLETE") {
133+
cli::cli_abort("Task failed")
134+
}
135+
}
105136
}
137+
138+
main()

0 commit comments

Comments
 (0)