Skip to content
55 linesCodeBlameRaw
1//! Workflow jobs' tokens: `G1T_TOKEN` (and `GITHUB_TOKEN`, its alias) for
2//! one job of a g1t Actions run. Each acts as the repository's workspace,
3//! reaches that repository only, holds the scopes the job's `permissions:`
4//! give it, and ends when the job does. See migration 0030.
5
6use g1t_contracts::identity::{CreateJobTokenArgs, CreatedAccessToken, RevokeJobTokensArgs};
7use g1t_contracts::time::SQL_NOW;
8use worker::Result;
9
10use crate::Identity;
11use crate::tokens::Grant;
12
13/// No job runs longer than a day, whatever its caller asks for.
14const MAX_JOB_TTL_SECONDS: u64 = 24 * 60 * 60 + 600;
15
16impl Identity {
17 pub async fn create_job_token(&self, a: CreateJobTokenArgs) -> Result<CreatedAccessToken> {
18 let created = self
19 .mint_for_workspace(
20 &a.workspace.id,
21 &a.name,
22 a.ttl_seconds.clamp(60, MAX_JOB_TTL_SECONDS),
23 &Grant::asked(&Some(a.scopes.clone())),
24 )
25 .await?;
26 self.db
27 .prepare("UPDATE access_tokens SET repo = ?, job_id = ?, job_run_id = ?, job_pulls = ? WHERE id = ?")
28 .bind(&[
29 format!("{}/{}", a.repo.namespace, a.repo.name).to_lowercase().into(),
30 a.job_id.as_str().into(),
31 a.run_id.as_str().into(),
32 u32::from(a.pull_requests).into(),
33 created.info.id.as_str().into(),
34 ])?
35 .run()
36 .await?;
37 Ok(created)
38 }
39
40 /// Ends a job's tokens: they stop working at once.
41 pub async fn revoke_job_tokens(&self, a: RevokeJobTokensArgs) -> Result<bool> {
42 if a.job_id.trim().is_empty() {
43 return Ok(false);
44 }
45 self.db
46 .prepare(format!(
47 "UPDATE access_tokens SET expires_at = {SQL_NOW}
48 WHERE job_id = ? AND (expires_at IS NULL OR expires_at > {SQL_NOW})"
49 ))
50 .bind(&[a.job_id.as_str().into()])?
51 .run()
52 .await?;
53 Ok(true)
54 }
55}