Serve /.well-known/source #227
No files matched your search
@@ -122,6 +122,7 @@ jobs:
|
||||
docker buildx build \
|
||||
--platform linux/amd64 \
|
||||
--provenance=false --sbom=false \
|
||||
--build-arg INBUXA_REVISION="${{ github.sha }}" \
|
||||
--tag "$IMAGE:$VERSION-amd64" \
|
||||
--tag "$IMAGE:$VERSION" \
|
||||
--push .
|
||||
@@ -163,6 +164,7 @@ jobs:
|
||||
docker buildx build \
|
||||
--platform linux/arm64 \
|
||||
--provenance=false --sbom=false \
|
||||
--build-arg INBUXA_REVISION="${{ github.sha }}" \
|
||||
--tag "$IMAGE:$VERSION-arm64" \
|
||||
--push .
|
||||
args=""
|
||||
|
||||
@@ -264,6 +264,7 @@ jobs:
|
||||
platforms: linux/${{ matrix.arch }}
|
||||
provenance: false
|
||||
sbom: false
|
||||
build-args: INBUXA_REVISION=${{ github.sha }}
|
||||
push: true
|
||||
tags: |
|
||||
${{ env.IMAGE }}:${{ env.VERSION }}-${{ matrix.arch }}
|
||||
|
||||
@@ -28,6 +28,11 @@ COPY --from=planner /recipe.json /recipe.json
|
||||
COPY vendor/ vendor/
|
||||
RUN RUSTFLAGS="$(cat /flags.txt)" cargo chef cook --target "$(cat /target.txt)" --release --no-default-features --features "sqlite postgres mysql rocks s3 redis azure nats" --recipe-path /recipe.json
|
||||
COPY . .
|
||||
# inbuxa: the commit being built, for /.well-known/source. The context has no
|
||||
# .git, so the release workflow passes it; a build without it serves no
|
||||
# source document.
|
||||
ARG INBUXA_REVISION=""
|
||||
ENV INBUXA_REVISION=${INBUXA_REVISION}
|
||||
RUN RUSTFLAGS="$(cat /flags.txt)" cargo build --target "$(cat /target.txt)" --release -p inbuxa --no-default-features --features "sqlite postgres mysql rocks s3 redis azure nats"
|
||||
RUN mv "/build/target/$(cat /target.txt)/release" "/output"
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ pub mod form;
|
||||
pub mod live; // inbuxa: monitoring (MON-20 to MON-24)
|
||||
pub mod request;
|
||||
pub mod scim; // inbuxa: SCIM 2.0 provisioning
|
||||
pub mod source; // inbuxa: /.well-known/source
|
||||
|
||||
use common::Inner;
|
||||
use std::sync::Arc;
|
||||
|
||||
@@ -350,6 +350,22 @@ impl ParseHttp for Server {
|
||||
};
|
||||
}
|
||||
}
|
||||
// inbuxa: where this build's source is (/.well-known/source)
|
||||
("source", &Method::GET | &Method::HEAD) => {
|
||||
// Limit anonymous requests
|
||||
self.is_http_anonymous_request_allowed(session.remote_ip)
|
||||
.await?;
|
||||
|
||||
return match crate::source::document() {
|
||||
Some(document) => {
|
||||
Ok(Resource::new("application/json", document.into_bytes())
|
||||
.into_http_response()
|
||||
.with_no_cache()
|
||||
.with_cors_unrestricted())
|
||||
}
|
||||
None => Err(trc::ResourceEvent::NotFound.into_err()),
|
||||
};
|
||||
}
|
||||
("mta-sts.txt", &Method::GET) => {
|
||||
// Limit anonymous requests
|
||||
self.is_http_anonymous_request_allowed(session.remote_ip)
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Coffey Labs LLC
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
//! `/.well-known/source`: what the server runs and where its source is, in
|
||||
//! the form https://coffeylabs.org/specs/well-known-source/ gives it.
|
||||
//!
|
||||
//! The server names its public repository and the commit it was built from.
|
||||
//! A build that doesn't know its commit says nothing, and the address answers
|
||||
//! 404, since a repository without a revision doesn't name the build.
|
||||
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct Document<'a> {
|
||||
version: u32,
|
||||
software: [Software<'a>; 1],
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct Software<'a> {
|
||||
name: &'a str,
|
||||
version: &'a str,
|
||||
license: &'a str,
|
||||
repository: &'a str,
|
||||
revision: &'a str,
|
||||
}
|
||||
|
||||
/// The document for this build, if it knows its commit.
|
||||
pub fn document() -> Option<String> {
|
||||
document_for(types::branding::BUILD_REVISION)
|
||||
}
|
||||
|
||||
fn document_for(revision: Option<&str>) -> Option<String> {
|
||||
let revision = revision.filter(|r| is_commit_id(r))?;
|
||||
serde_json::to_string(&Document {
|
||||
version: 1,
|
||||
software: [Software {
|
||||
name: types::brand_server!(),
|
||||
version: types::brand_version!(),
|
||||
license: "AGPL-3.0-only",
|
||||
repository: types::brand_repository!(),
|
||||
revision,
|
||||
}],
|
||||
})
|
||||
.ok()
|
||||
}
|
||||
|
||||
/// A full commit id: 40 hex digits (SHA-1) or 64 (SHA-256).
|
||||
fn is_commit_id(revision: &str) -> bool {
|
||||
matches!(revision.len(), 40 | 64) && revision.bytes().all(|b| b.is_ascii_hexdigit())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::document_for;
|
||||
|
||||
const COMMIT: &str = "f17b0943c2a1d5e8b7f6a9c0d1e2f3a4b5c6d7e8";
|
||||
|
||||
#[test]
|
||||
fn names_the_repository_and_commit() {
|
||||
let doc: serde_json::Value =
|
||||
serde_json::from_str(&document_for(Some(COMMIT)).unwrap()).unwrap();
|
||||
assert_eq!(doc["version"], 1);
|
||||
let software = doc["software"].as_array().unwrap();
|
||||
assert_eq!(software.len(), 1);
|
||||
assert_eq!(software[0]["name"], types::brand_server!());
|
||||
assert_eq!(software[0]["version"], types::brand_version!());
|
||||
assert_eq!(software[0]["license"], "AGPL-3.0-only");
|
||||
assert_eq!(software[0]["repository"], types::brand_repository!());
|
||||
assert_eq!(software[0]["revision"], COMMIT);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn says_nothing_without_a_full_commit() {
|
||||
let not_hex = COMMIT.replace('f', "g");
|
||||
for revision in [
|
||||
None,
|
||||
Some(""),
|
||||
Some("f17b094"),
|
||||
Some("v27.1"),
|
||||
Some(not_hex.as_str()),
|
||||
] {
|
||||
assert_eq!(document_for(revision), None, "{revision:?}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -52,6 +52,19 @@ macro_rules! brand_url {
|
||||
};
|
||||
}
|
||||
|
||||
/// The public repository the server's source is published in, named in
|
||||
/// `/.well-known/source`.
|
||||
#[macro_export]
|
||||
macro_rules! brand_repository {
|
||||
() => {
|
||||
"https://git.coffeylabs.org/inbuxa/inbuxa-server"
|
||||
};
|
||||
}
|
||||
|
||||
/// The commit this build was made from, as the release build passes it in
|
||||
/// `INBUXA_REVISION`. A build that wasn't told has none.
|
||||
pub const BUILD_REVISION: Option<&str> = option_env!("INBUXA_REVISION");
|
||||
|
||||
/// Reads one of the server's environment variables by its unprefixed name,
|
||||
/// such as `RECOVERY_ADMIN`, from `INBUXA_<name>`.
|
||||
///
|
||||
|
||||
Reference in new issue
Block a user