Add expires_at field for impersonation_tokens POST request
Diff
Cargo.lock | 2 ++
Cargo.toml | 1 +
src/config.rs | 10 ++++++++++
src/main.rs | 4 ++--
src/util.rs | 2 +-
src/git_command_handlers/ls_refs.rs | 4 ++--
src/providers/gitlab.rs | 12 +++++++++++-
7 files changed, 27 insertions(+), 8 deletions(-)
@@ -556,6 +556,7 @@
"shlex",
"thrussh",
"thrussh-keys",
"time",
"tokio",
"tokio-util",
"toml",
@@ -1522,6 +1523,7 @@
dependencies = [
"libc",
"num_threads",
"serde",
]
[[package]]
@@ -31,6 +31,7 @@
serde_json = "1"
sha1 = "0.10"
shlex = "1.1"
time = { version = "0.3", features = ["serde"] }
tracing = "0.1"
tracing-subscriber = "0.3"
thrussh = "0.33"
@@ -1,8 +1,9 @@
#![allow(clippy::module_name_repetitions)]
use clap::Parser;
use serde::{de::DeserializeOwned, Deserialize};
use std::{net::SocketAddr, path::PathBuf};
use time::Duration;
use url::Url;
#[derive(Parser)]
@@ -25,6 +26,15 @@
pub struct GitlabConfig {
pub uri: Url,
pub admin_token: String,
#[serde(default = "GitlabConfig::default_token_expiry")]
pub token_expiry: Duration,
}
impl GitlabConfig {
#[must_use]
const fn default_token_expiry() -> Duration {
Duration::days(30)
}
}
pub fn from_toml_path<T: DeserializeOwned>(path: &str) -> Result<T, std::io::Error> {
@@ -84,7 +84,7 @@
.ok_or_else(|| anyhow!("failed to generate server private key"))?;
let thrussh_keys::key::KeyPair::Ed25519(key) = key;
std::fs::write(server_private_key, &key.key)?;
std::fs::write(server_private_key, key.key)?;
thrussh_keys::key::KeyPair::Ed25519(key)
};
@@ -350,7 +350,7 @@
dyn Future<Output = Result<T, <Handler<U> as thrussh::server::Handler>::Error>> + Send;
#[allow(clippy::type_complexity)]
impl<'a, U: UserProvider + PackageProvider + Send + Sync + 'static> thrussh::server::Handler
impl<U: UserProvider + PackageProvider + Send + Sync + 'static> thrussh::server::Handler
for Handler<U>
{
type Error = anyhow::Error;
@@ -9,7 +9,7 @@
#[must_use]
pub fn format_fingerprint(fingerprint: &str) -> String {
format!("SHA256:{}", fingerprint)
format!("SHA256:{fingerprint}")
}
@@ -19,10 +19,10 @@
_metadata: &[Bytes],
commit_hash: &HashOutput,
) -> Result<(), anyhow::Error> {
let commit_hash = hex::encode(&commit_hash);
let commit_hash = hex::encode(commit_hash);
handle.write(PktLine::Data(
format!("{} HEAD symref-target:refs/heads/master", commit_hash).as_bytes(),
format!("{commit_hash} HEAD symref-target:refs/heads/master").as_bytes(),
))?;
handle.write(PktLine::Flush)?;
handle.flush(session, channel);
@@ -8,12 +8,14 @@
use reqwest::header;
use serde::{Deserialize, Serialize};
use std::{borrow::Cow, sync::Arc};
use time::{Duration, OffsetDateTime};
use tracing::{info_span, instrument, Instrument};
use url::Url;
pub struct Gitlab {
client: reqwest::Client,
base_url: Url,
token_expiry: Duration,
}
impl Gitlab {
@@ -29,6 +31,7 @@
.default_headers(headers)
.build()?,
base_url: config.uri.join("api/v4/")?,
token_expiry: config.token_expiry,
})
}
}
@@ -41,9 +44,8 @@
username_password: &str,
) -> anyhow::Result<Option<User>> {
let mut splitter = username_password.splitn(2, ':');
let (username, password) = match (splitter.next(), splitter.next()) {
(Some(username), Some(password)) => (username, password),
_ => return Ok(None),
let (Some(username), Some(password)) = (splitter.next(), splitter.next()) else {
return Ok(None);
};
if username == "gitlab-ci-token" {
@@ -95,6 +97,9 @@
)
.json(&GitlabImpersonationTokenRequest {
name: env!("CARGO_PKG_NAME"),
expires_at: (OffsetDateTime::now_utc() + self.token_expiry)
.date()
.to_string(),
scopes: vec!["api"],
})
.send()
@@ -273,6 +278,7 @@
#[derive(Serialize)]
pub struct GitlabImpersonationTokenRequest {
name: &'static str,
expires_at: String,
scopes: Vec<&'static str>,
}