rebranding herald => steep
ci/woodpecker/push/tests Pipeline was successful

This commit is contained in:
qpismont committed 2026-09-29 18:36:01 +00:00
1 parent 9f03384bc9
commit f5f0d3999e
30 files changed
+96 -93

No files matched your search

+3 -3
View File
@@ -1,5 +1,5 @@
{ {
"name": "herald", "name": "steep",
"build": { "build": {
"dockerfile": "Dockerfile", "dockerfile": "Dockerfile",
"args": { "args": {
@@ -17,8 +17,8 @@
"extensions": ["fill-labs.dependi", "rust-lang.rust-analyzer", "tamasfe.even-better-toml"] "extensions": ["fill-labs.dependi", "rust-lang.rust-analyzer", "tamasfe.even-better-toml"]
} }
}, },
"workspaceMount": "source=${localWorkspaceFolder},target=/workspaces/herald,type=bind", "workspaceMount": "source=${localWorkspaceFolder},target=/workspaces/steep,type=bind",
"workspaceFolder": "/workspaces/herald", "workspaceFolder": "/workspaces/steep",
"runArgs": ["--userns=keep-id", "--security-opt", "label=disable"], "runArgs": ["--userns=keep-id", "--security-opt", "label=disable"],
"appPort": [3000] "appPort": [3000]
} }
+1 -1
View File
@@ -26,4 +26,4 @@ steps:
volumes: volumes:
- /data/woodpecker-builds:/data - /data/woodpecker-builds:/data
commands: commands:
- buildah bud -f Containerfile -t herald-ci . - buildah bud -f Containerfile -t steep-ci .
Generated
+28 -28
View File
@@ -766,34 +766,6 @@ version = "0.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
[[package]]
name = "herald-server"
version = "1.2.0"
dependencies = [
"anyhow",
"axum",
"devcontainer-rs",
"dotenvy",
"futures-util",
"hex",
"metrics",
"metrics-exporter-prometheus",
"reqwest",
"ring",
"sentry",
"sentry-anyhow",
"serde",
"serde_json",
"tempfile",
"thiserror",
"tokio",
"tokio-util",
"tower",
"tower-http 0.7.1",
"tracing",
"tracing-subscriber",
]
[[package]] [[package]]
name = "hex" name = "hex"
version = "0.4.3" version = "0.4.3"
@@ -2236,6 +2208,34 @@ version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
[[package]]
name = "steep-server"
version = "1.2.0"
dependencies = [
"anyhow",
"axum",
"devcontainer-rs",
"dotenvy",
"futures-util",
"hex",
"metrics",
"metrics-exporter-prometheus",
"reqwest",
"ring",
"sentry",
"sentry-anyhow",
"serde",
"serde_json",
"tempfile",
"thiserror",
"tokio",
"tokio-util",
"tower",
"tower-http 0.7.1",
"tracing",
"tracing-subscriber",
]
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.119" version = "2.0.119"
+1 -1
View File
@@ -1,6 +1,6 @@
[workspace] [workspace]
members = [ members = [
"crates/herald-server", "crates/steep-server",
"crates/devcontainer-rs", "crates/devcontainer-rs",
] ]
resolver = "3" resolver = "3"
+4 -4
View File
@@ -5,14 +5,14 @@ WORKDIR /app
COPY Cargo.toml Cargo.lock ./ COPY Cargo.toml Cargo.lock ./
COPY crates/ crates/ COPY crates/ crates/
RUN cargo build --release --package herald-server RUN cargo build --release --package steep-server
FROM debian:trixie-slim FROM debian:trixie-slim
# git clones the pull request. ca-certificates is what every HTTPS call needs # git clones the pull request. ca-certificates is what every HTTPS call needs
# (Gitea, OpenRouter, git). The shared libraries are the non-base ones the binary # (Gitea, OpenRouter, git). The shared libraries are the non-base ones the binary
# links against, as reported by `ldd target/release/herald-server`; libc, libm # links against, as reported by `ldd target/release/steep-server`; libc, libm
# and libgcc_s come from the base image. # and libgcc_s come from the base image.
RUN apt-get update && apt-get install -y --no-install-recommends \ RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates \ ca-certificates \
@@ -24,8 +24,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
WORKDIR /app WORKDIR /app
COPY --from=builder /app/target/release/herald-server ./herald-server COPY --from=builder /app/target/release/steep-server ./steep-server
# Exec form, so the binary is PID 1 and receives the SIGTERM it handles to shut # Exec form, so the binary is PID 1 and receives the SIGTERM it handles to shut
# down gracefully. # down gracefully.
CMD ["./herald-server"] CMD ["./steep-server"]
+28 -24
View File
@@ -1,6 +1,10 @@
# Herald ![Steep — Let your code steep](banniere_readme.png)
Herald is a Gitea bot that performs automated AI-powered code reviews on pull requests using [OpenRouter](https://openrouter.ai/). # Steep
*Let your code steep.*
Steep is a Gitea bot that performs automated AI-powered code reviews on pull requests using [OpenRouter](https://openrouter.ai/).
## Features ## Features
@@ -10,18 +14,18 @@ Herald is a Gitea bot that performs automated AI-powered code reviews on pull re
- Graceful shutdown — in-progress reviews finish before the process exits - Graceful shutdown — in-progress reviews finish before the process exits
- Error tracking via Sentry - Error tracking via Sentry
- Prometheus metrics endpoint for monitoring - Prometheus metrics endpoint for monitoring
- Tiny memory footprint (~4MB) thanks to Rust - Lightweight, performant Rust service with Prometheus metrics and Sentry error tracking
## Installation ## Installation
**Requirements:** Rust toolchain ([rustup.rs](https://rustup.rs)) **Requirements:** Rust toolchain ([rustup.rs](https://rustup.rs))
```sh ```sh
cargo build --release cargo build --release -p steep-server
./target/release/herald ./target/release/steep-server
``` ```
Herald reads its configuration from environment variables (a `.env` file is supported): Steep reads its configuration from environment variables (a `.env` file is supported):
| Variable | Description | | Variable | Description |
|---|---| |---|---|
@@ -38,11 +42,11 @@ Herald reads its configuration from environment variables (a `.env` file is supp
| `SENTRY_DSN` | *(optional)* Sentry DSN for error tracking | | `SENTRY_DSN` | *(optional)* Sentry DSN for error tracking |
| `RUST_LOG` | *(optional)* Log level, defaults to `info` | | `RUST_LOG` | *(optional)* Log level, defaults to `info` |
| `SANDBOX_MAX_ITERATIONS` | *(optional)* Maximum number of tool-calling iterations per sandboxed review. Defaults to `8` | | `SANDBOX_MAX_ITERATIONS` | *(optional)* Maximum number of tool-calling iterations per sandboxed review. Defaults to `8` |
| `DOCKER_HOST` | *(optional)* Container daemon socket Herald drives, e.g. `unix:///run/user/1000/podman/podman.sock` for a rootless podman. Defaults to `unix:///var/run/docker.sock` | | `DOCKER_HOST` | *(optional)* Container daemon socket Steep drives, e.g. `unix:///run/user/1000/podman/podman.sock` for a rootless podman. Defaults to `unix:///var/run/docker.sock` |
## Sandboxed reviews ## Sandboxed reviews
Herald reviews pull requests inside an ephemeral Steep reviews pull requests inside an ephemeral
[Dev Container](https://containers.dev/). For each review it: [Dev Container](https://containers.dev/). For each review it:
1. clones the pull request head into a temporary directory, 1. clones the pull request head into a temporary directory,
@@ -66,14 +70,14 @@ Each comment is tagged with a severity — `bug`, `security`, `performance` or
`maintainability` — shown at the start of the comment, and the summary also lists `maintainability` — shown at the start of the comment, and the summary also lists
what the pull request does well. what the pull request does well.
Herald drives the container daemon through its socket: `DOCKER_HOST` (default Steep drives the container daemon through its socket: `DOCKER_HOST` (default
`unix:///var/run/docker.sock`), which covers both docker and podman's `unix:///var/run/docker.sock`), which covers both docker and podman's
Docker-compatible socket. When the repository contains a Docker-compatible socket. When the repository contains a
`.devcontainer/devcontainer.json` (or `.devcontainer.json`), Herald uses it; `.devcontainer/devcontainer.json` (or `.devcontainer.json`), Steep uses it;
otherwise it falls back to a default devcontainer that pulls `debian:stable-slim` otherwise it falls back to a default devcontainer that pulls `debian:stable-slim`
and runs the review in `/workspace`. and runs the review in `/workspace`.
Herald can therefore run inside a container with only that socket mounted (no Steep can therefore run inside a container with only that socket mounted (no
shared workspace directory is required): the clone is streamed to the daemon over shared workspace directory is required): the clone is streamed to the daemon over
the socket, like the build context, instead of being bind-mounted from a host the socket, like the build context, instead of being bind-mounted from a host
path the daemon would have to see. This is the setup the `Containerfile` path the daemon would have to see. This is the setup the `Containerfile`
@@ -82,7 +86,7 @@ produces, e.g.:
```sh ```sh
podman run --env-file=.env -p 3001:3001 \ podman run --env-file=.env -p 3001:3001 \
-v /run/user/$(id -u)/podman/podman.sock:/var/run/docker.sock \ -v /run/user/$(id -u)/podman/podman.sock:/var/run/docker.sock \
herald:latest steep:latest
``` ```
The `runArgs` of that file are ignored: they come from an untrusted pull request, The `runArgs` of that file are ignored: they come from an untrusted pull request,
@@ -107,28 +111,28 @@ Open the project and reopen it in the container — the Rust toolchain is pre-in
```sh ```sh
rustup toolchain install stable rustup toolchain install stable
cargo run cargo run -p steep-server
``` ```
Copy `.env.example` to `.env` and fill in your values before running. Copy `.env.example` to `.env` and fill in your values before running.
## Metrics ## Metrics
Herald optionally exposes a Prometheus metrics endpoint, useful for scraping with an [OpenTelemetry Collector](https://opentelemetry.io/docs/collector/) or any Prometheus-compatible scraper. Steep optionally exposes a Prometheus metrics endpoint, useful for scraping with an [OpenTelemetry Collector](https://opentelemetry.io/docs/collector/) or any Prometheus-compatible scraper.
Set `METRICS_BIND_ADDR` (e.g. `0.0.0.0:9100`) to enable it. The metrics are then available at `http://<host>:9100/metrics`. Set `METRICS_BIND_ADDR` (e.g. `0.0.0.0:9100`) to enable it. The metrics are then available at `http://<host>:9100/metrics`. The metric namespace changed from `herald_*` to `steep_*`; update any dashboards or alerts that use the old names.
### Exposed metrics ### Exposed metrics
| Metric | Type | Description | | Metric | Type | Description |
|---|---|---| |---|---|---|
| `herald_webhooks_received_total` | counter | Total webhooks received (label: `event_type`) | | `steep_webhooks_received_total` | counter | Total webhooks received (label: `event_type`) |
| `herald_webhooks_duplicate_total` | counter | Webhooks rejected as duplicates (label: `event_type`) | | `steep_webhooks_duplicate_total` | counter | Webhooks rejected as duplicates (label: `event_type`) |
| `herald_webhooks_channel_full_total` | counter | Webhooks dropped because the bot channel was full (label: `event_type`) | | `steep_webhooks_channel_full_total` | counter | Webhooks dropped because the bot channel was full (label: `event_type`) |
| `herald_bot_tasks_active` | gauge | Bot tasks currently in progress | | `steep_bot_tasks_active` | gauge | Bot tasks currently in progress |
| `herald_bot_tasks_completed_total` | counter | Bot tasks completed successfully (label: `event_type`) | | `steep_bot_tasks_completed_total` | counter | Bot tasks completed successfully (label: `event_type`) |
| `herald_bot_tasks_failed_total` | counter | Bot tasks that failed (label: `event_type`) | | `steep_bot_tasks_failed_total` | counter | Bot tasks that failed (label: `event_type`) |
| `herald_openrouter_cost_cents_total` | counter | Total OpenRouter cost in cents (divide by 100 for USD) | | `steep_openrouter_cost_cents_total` | counter | Total OpenRouter cost in cents (divide by 100 for USD) |
### OTel collector example ### OTel collector example
@@ -137,10 +141,10 @@ receivers:
prometheus: prometheus:
config: config:
scrape_configs: scrape_configs:
- job_name: herald - job_name: steep
scrape_interval: 15s scrape_interval: 15s
static_configs: static_configs:
- targets: ["herald:9100"] - targets: ["steep:9100"]
service: service:
pipelines: pipelines:
+3 -3
View File
@@ -13,9 +13,9 @@
## 1.3 — Typed action routing — planned ## 1.3 — Typed action routing — planned
- Introduce a type-safe model output for the action Herald should take, such as `Review` or `Implementation`. - Introduce a type-safe model output for the action Steep should take, such as `Review` or `Implementation`.
- Route review requests (for example, “@herald, review this PR”) to the existing review flow. - Route review requests (for example, “@steep, review this PR”) to the existing review flow.
- Recognize implementation requests (for example, “@herald, rename method `XXX` to `YYY`”) and establish their dispatch path. Execution of implementation requests is planned for 2.0. - Recognize implementation requests (for example, “@steep, rename method `XXX` to `YYY`”) and establish their dispatch path. Execution of implementation requests is planned for 2.0.
## 2.0 — Implementation requests — planned ## 2.0 — Implementation requests — planned
Binary file not shown.

After

Width:  |  Height:  |  Size: 1009 KiB

+1 -1
View File
@@ -7,7 +7,7 @@
//! l'intérieur du container en cours d'exécution. //! l'intérieur du container en cours d'exécution.
//! //!
//! Le daemon est joint par son **socket** (celui de l'hôte, monté dans le //! Le daemon est joint par son **socket** (celui de l'hôte, monté dans le
//! container de Herald) : [`ContainerRuntime::connect`] suit `DOCKER_HOST` comme //! container de Steep) : [`ContainerRuntime::connect`] suit `DOCKER_HOST` comme
//! le fait le CLI `docker`, et retombe sur le socket local. Aucun binaire de //! le fait le CLI `docker`, et retombe sur le socket local. Aucun binaire de
//! runtime n'est donc requis dans l'image, et `podman` fonctionne de la même //! runtime n'est donc requis dans l'image, et `podman` fonctionne de la même
//! façon dès lors qu'il expose son socket compatible Docker. //! façon dès lors qu'il expose son socket compatible Docker.
+2 -2
View File
@@ -112,7 +112,7 @@ impl TryFrom<(DevContainerSchema, PathBuf)> for DevContainer {
/// La spécification veut que `${localEnv:VAR}` soit lu dans l'environnement du /// La spécification veut que `${localEnv:VAR}` soit lu dans l'environnement du
/// client ; ici le `devcontainer.json` vient d'une **pull request**, donc de code /// client ; ici le `devcontainer.json` vient d'une **pull request**, donc de code
/// non fiable : lire l'environnement du processus lui permettrait de récupérer /// non fiable : lire l'environnement du processus lui permettrait de récupérer
/// `GITEA_TOKEN`, `OPEN_ROUTER_API_KEY` ou n'importe quel autre secret de Herald et /// `GITEA_TOKEN`, `OPEN_ROUTER_API_KEY` ou n'importe quel autre secret de Steep et
/// de l'exfiltrer depuis un `build.args`, un `containerEnv`, son Dockerfile ou un /// de l'exfiltrer depuis un `build.args`, un `containerEnv`, son Dockerfile ou un
/// hook. L'environnement n'est donc **jamais** consulté : seule la valeur par /// hook. L'environnement n'est donc **jamais** consulté : seule la valeur par
/// défaut est utilisée, et une référence sans défaut devient une chaîne vide. /// défaut est utilisée, et une référence sans défaut devient une chaîne vide.
@@ -272,7 +272,7 @@ mod tests {
unsafe { std::env::set_var("DEVCONTAINER_TEST_SECRET", "s3cret") }; unsafe { std::env::set_var("DEVCONTAINER_TEST_SECRET", "s3cret") };
// Le `devcontainer.json` vient d'une pull request : résoudre la référence // Le `devcontainer.json` vient d'une pull request : résoudre la référence
// depuis l'environnement de Herald y exposerait ses jetons. // depuis l'environnement de Steep y exposerait ses jetons.
assert_eq!( assert_eq!(
substitute_local_env("${localEnv:DEVCONTAINER_TEST_SECRET}"), substitute_local_env("${localEnv:DEVCONTAINER_TEST_SECRET}"),
"" ""
@@ -1,5 +1,5 @@
[package] [package]
name = "herald-server" name = "steep-server"
version = "1.2.0" version = "1.2.0"
edition = "2024" edition = "2024"
@@ -47,7 +47,7 @@ pub async fn start(app_state: AppState, shutdown: CancellationToken) -> anyhow::
} }
async fn root() -> &'static str { async fn root() -> &'static str {
"Hi, i'm Herald :)" "Hi, I'm Steep :)"
} }
#[instrument(skip(app_state), fields(webhook_type), err)] #[instrument(skip(app_state), fields(webhook_type), err)]
File renamed without changes.
@@ -875,7 +875,7 @@ mod tests {
#[test] #[test]
fn generated_lockfiles_are_ignored() { fn generated_lockfiles_are_ignored() {
assert!(is_ignored("Cargo.lock")); assert!(is_ignored("Cargo.lock"));
assert!(is_ignored("crates/herald-server/Cargo.lock")); assert!(is_ignored("crates/steep-server/Cargo.lock"));
assert!(is_ignored("package-lock.json")); assert!(is_ignored("package-lock.json"));
assert!(is_ignored("web/yarn.lock")); assert!(is_ignored("web/yarn.lock"));
assert!(is_ignored("go.sum")); assert!(is_ignored("go.sum"));
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -76,7 +76,7 @@ async fn run() -> anyhow::Result<()> {
model = %config.open_router_model, model = %config.open_router_model,
gitea_url = %config.gitea_url, gitea_url = %config.gitea_url,
bot_name = %gitea_user.login, bot_name = %gitea_user.login,
"Starting Herald" "Starting Steep"
); );
let open_router_client = OpenRouterClient::new( let open_router_client = OpenRouterClient::new(
@@ -3,73 +3,72 @@ use std::{net::SocketAddr, str::FromStr};
use metrics::{Unit, counter, describe_counter, describe_gauge, gauge}; use metrics::{Unit, counter, describe_counter, describe_gauge, gauge};
pub fn webhook_received(event_type: &str) { pub fn webhook_received(event_type: &str) {
counter!("herald_webhooks_received_total", "event_type" => event_type.to_string()).increment(1); counter!("steep_webhooks_received_total", "event_type" => event_type.to_string()).increment(1);
} }
pub fn webhook_duplicate(event_type: &str) { pub fn webhook_duplicate(event_type: &str) {
counter!("herald_webhooks_duplicate_total", "event_type" => event_type.to_string()) counter!("steep_webhooks_duplicate_total", "event_type" => event_type.to_string()).increment(1);
.increment(1);
} }
pub fn webhook_channel_full(event_type: &str) { pub fn webhook_channel_full(event_type: &str) {
counter!("herald_webhooks_channel_full_total", "event_type" => event_type.to_string()) counter!("steep_webhooks_channel_full_total", "event_type" => event_type.to_string())
.increment(1); .increment(1);
} }
pub fn increment_task_active() { pub fn increment_task_active() {
gauge!("herald_bot_tasks_active").increment(1.0); gauge!("steep_bot_tasks_active").increment(1.0);
} }
pub fn decrement_task_active() { pub fn decrement_task_active() {
gauge!("herald_bot_tasks_active").decrement(1.0); gauge!("steep_bot_tasks_active").decrement(1.0);
} }
pub fn task_completed(event_type: &str) { pub fn task_completed(event_type: &str) {
counter!("herald_bot_tasks_completed_total", "event_type" => event_type.to_string()) counter!("steep_bot_tasks_completed_total", "event_type" => event_type.to_string())
.increment(1); .increment(1);
} }
pub fn task_failed(event_type: &str) { pub fn task_failed(event_type: &str) {
counter!("herald_bot_tasks_failed_total", "event_type" => event_type.to_string()).increment(1); counter!("steep_bot_tasks_failed_total", "event_type" => event_type.to_string()).increment(1);
} }
pub fn openrouter_cost_usd(cost: f64) { pub fn openrouter_cost_usd(cost: f64) {
counter!("herald_openrouter_cost_cents_total").increment((cost * 100.0).round() as u64); counter!("steep_openrouter_cost_cents_total").increment((cost * 100.0).round() as u64);
} }
pub fn describe() { pub fn describe() {
describe_counter!( describe_counter!(
"herald_webhooks_received_total", "steep_webhooks_received_total",
Unit::Count, Unit::Count,
"Total webhooks received" "Total webhooks received"
); );
describe_counter!( describe_counter!(
"herald_webhooks_duplicate_total", "steep_webhooks_duplicate_total",
Unit::Count, Unit::Count,
"Webhooks rejected as duplicates" "Webhooks rejected as duplicates"
); );
describe_counter!( describe_counter!(
"herald_webhooks_channel_full_total", "steep_webhooks_channel_full_total",
Unit::Count, Unit::Count,
"Webhooks dropped because the bot channel was full" "Webhooks dropped because the bot channel was full"
); );
describe_gauge!( describe_gauge!(
"herald_bot_tasks_active", "steep_bot_tasks_active",
Unit::Count, Unit::Count,
"Bot tasks currently in progress" "Bot tasks currently in progress"
); );
describe_counter!( describe_counter!(
"herald_bot_tasks_completed_total", "steep_bot_tasks_completed_total",
Unit::Count, Unit::Count,
"Bot tasks completed successfully" "Bot tasks completed successfully"
); );
describe_counter!( describe_counter!(
"herald_bot_tasks_failed_total", "steep_bot_tasks_failed_total",
Unit::Count, Unit::Count,
"Bot tasks that failed" "Bot tasks that failed"
); );
describe_counter!( describe_counter!(
"herald_openrouter_cost_cents_total", "steep_openrouter_cost_cents_total",
Unit::Count, Unit::Count,
"Total OpenRouter cost in cents (divide by 100 for USD)" "Total OpenRouter cost in cents (divide by 100 for USD)"
); );
@@ -1,10 +1,10 @@
//! Minimal OpenRouter chat-completions client. //! Minimal OpenRouter chat-completions client.
//! //!
//! Herald only needs a non-streaming `POST /chat/completions` with optional //! Steep only needs a non-streaming `POST /chat/completions` with optional
//! tool calling, so the wire types are implemented in-tree instead of pulling a //! tool calling, so the wire types are implemented in-tree instead of pulling a
//! third-party SDK (and its own `reqwest` version) into the workspace. //! third-party SDK (and its own `reqwest` version) into the workspace.
//! //!
//! Only the response fields Herald consumes are modelled: `content`, //! Only the response fields Steep consumes are modelled: `content`,
//! `tool_calls` and `usage.cost`. Unknown fields are ignored. //! `tool_calls` and `usage.cost`. Unknown fields are ignored.
use std::time::Duration; use std::time::Duration;
@@ -174,7 +174,7 @@ struct ChatRequest<'a> {
tool_choice: &'a str, tool_choice: &'a str,
} }
/// OpenRouter reasoning config; Herald always asks for reasoning. /// OpenRouter reasoning config; Steep always asks for reasoning.
#[derive(Serialize)] #[derive(Serialize)]
struct Reasoning { struct Reasoning {
enabled: bool, enabled: bool,
@@ -214,10 +214,10 @@ async fn clone_pull_request(
/// Rend le clone lisible par les utilisateurs du container sandbox. /// Rend le clone lisible par les utilisateurs du container sandbox.
/// ///
/// Le container peut ne pas avoir les mêmes uid que Herald (podman rootless /// Le container peut ne pas avoir les mêmes uid que Steep (podman rootless
/// mappe les uid à travers des plages subuid), et l'umask de l'opérateur peut être /// mappe les uid à travers des plages subuid), et l'umask de l'opérateur peut être
/// restrictif : sans cela, les outils de la sandbox échouent en `Permission /// restrictif : sans cela, les outils de la sandbox échouent en `Permission
/// denied` sur des fichiers que Herald vient de cloner lui-même. /// denied` sur des fichiers que Steep vient de cloner lui-même.
async fn make_readable(repo_dir: &Path) -> anyhow::Result<()> { async fn make_readable(repo_dir: &Path) -> anyhow::Result<()> {
let output = tokio::process::Command::new("chmod") let output = tokio::process::Command::new("chmod")
.args(["-R", "a+rX"]) .args(["-R", "a+rX"])
File renamed without changes.
File renamed without changes.
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 843 KiB

+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -euo pipefail set -euo pipefail
IMAGE="tintounn/herald" IMAGE="tintounn/steep"
if [ -z "${CI_COMMIT_TAG:-}" ]; then if [ -z "${CI_COMMIT_TAG:-}" ]; then
echo "Error: CI_COMMIT_TAG is not set" >&2 echo "Error: CI_COMMIT_TAG is not set" >&2