Compare commits

..
8 Commits
Author SHA1 Message Date
ninjasurge 7406c292a1 merge upstream 2026-04-04 12:49:28 -05:00
NinjaSurge 427475651c Merge branch 'github-starred-main' 2026-03-25 18:51:08 -05:00
NinjaSurge ae0c8bf98a Merge branch 'fix-issue-1022' 2026-02-12 09:39:30 -06:00
NinjaSurge a7592f4561 Merge branch 'fix-issue-1022' of https://github.com/litlmike/komodo into fix-issue-1022 2026-02-12 09:37:28 -06:00
rootandNinjaSurge a199c8fe27 fix: refresh login options when OIDC client is re-initialized
The GetLoginOptions response was cached in a OnceLock, meaning it was
computed once at startup and never updated. When the OIDC client was
re-initialized (e.g. after config changes), the login options endpoint
would still return the stale cached value, causing the UI to show
outdated OIDC button state.

Replace the static OnceLock cache with a function that reads the
current OIDC client state on each request, so the response always
reflects whether OIDC is currently available.

Also add a 30-second polling interval to the frontend's login options
query so the login page picks up server-side changes without requiring
a hard refresh.

Fixes #1022
2026-02-12 09:37:19 -06:00
ninjasurge f7296c73b1 Merge pull request 'fix: prevent custom registry org input from deselecting' (#1) from fix-issue-1094 into main
Reviewed-on: ComputerSurge/komodo#1
2026-02-11 19:32:25 -06:00
root 0eaf8b5f01 fix: refresh login options when OIDC client is re-initialized
The GetLoginOptions response was cached in a OnceLock, meaning it was
computed once at startup and never updated. When the OIDC client was
re-initialized (e.g. after config changes), the login options endpoint
would still return the stale cached value, causing the UI to show
outdated OIDC button state.

Replace the static OnceLock cache with a function that reads the
current OIDC client state on each request, so the response always
reflects whether OIDC is currently available.

Also add a 30-second polling interval to the frontend's login options
query so the login page picks up server-side changes without requiring
a hard refresh.

Fixes #1022
2026-02-07 20:34:53 -08:00
Voice Typer User 6919582f69 fix: prevent custom registry org input from deselecting
The ImageRegistryConfig component's key included registry.organization,
which caused React to remount the component on every keystroke when
typing a custom organization name. This destroyed the OrganizationSelector's
internal customMode state, causing the input to deselect after each character.

Using a stable index-based key preserves component identity during edits.

Closes #1094
2026-02-06 16:04:35 -08:00
400 changed files with 10281 additions and 10357 deletions
+1 -4
View File
@@ -1,5 +1,2 @@
[alias]
xtask = "run --package xtask --"
[build]
rustflags = ["-Wunused-crate-dependencies"]
rustflags = ["-Wunused-crate-dependencies"]
Generated
+830 -1666
View File
File diff suppressed because it is too large Load Diff
+29 -31
View File
@@ -3,19 +3,21 @@ resolver = "2"
members = [
"bin/*",
"lib/*",
"xtask",
"client/core/rs",
"client/periphery/rs",
]
[workspace.package]
version = "2.2.0"
version = "2.1.1"
edition = "2024"
authors = ["mbecker20 <becker.maxh@gmail.com>"]
license = "GPL-3.0-or-later"
repository = "https://github.com/moghtech/komodo"
homepage = "https://komo.do"
[profile.release]
strip = "debuginfo"
[workspace.dependencies]
# LOCAL
komodo_client = { path = "client/core/rs" }
@@ -31,29 +33,29 @@ git = { path = "lib/git" }
# MOGH
slack = { version = "2.0.0", package = "slack_client_rs", default-features = false, features = ["rustls"] }
mogh_error = { version = "1.0.4", default-features = false }
mogh_error = { version = "1.0.3", default-features = false }
derive_default_builder = "0.1.8"
async_timing_util = "1.1.0"
mogh_auth_client = "1.5.0"
mogh_auth_server = "1.5.0"
mogh_auth_client = "1.2.2"
mogh_auth_server = "1.2.13"
mogh_secret_file = "1.0.1"
mogh_validations = "1.0.1"
mogh_rate_limit = "1.0.1"
partial_derive2 = "0.5.0"
partial_derive2 = "0.4.5"
mongo_indexed = "2.0.2"
mogh_resolver = "1.0.0"
mogh_config = "1.1.0"
mogh_config = "1.0.5"
mogh_logger = "1.3.3"
mogh_server = "1.5.0"
mogh_server = "1.4.5"
toml_pretty = "2.0.0"
mogh_cache = "1.1.2"
mogh_cache = "1.1.1"
mogh_pki = "1.1.3"
mungos = "3.2.2"
svi = "1.2.0"
# ASYNC
reqwest = { version = "0.13.3", default-features = false, features = ["json", "stream", "form", "query", "rustls"] }
tokio = { version = "1.52.2", features = ["full"] }
reqwest = { version = "0.13.2", default-features = false, features = ["json", "stream", "form", "query", "rustls"] }
tokio = { version = "1.50.0", features = ["full"] }
tokio-util = { version = "0.7.18", features = ["io", "codec"] }
tokio-stream = { version = "0.1.18", features = ["sync"] }
pin-project-lite = "0.2.17"
@@ -62,16 +64,16 @@ arc-swap = "1.9.0"
# SERVER
tokio-tungstenite = { version = "0.29.0", features = ["rustls-tls-native-roots"] }
axum = { version = "0.8.9", features = ["ws", "json", "macros"] }
axum-extra = { version = "0.12.6", features = ["typed-header"] }
axum = { version = "0.8.8", features = ["ws", "json", "macros"] }
axum-extra = { version = "0.12.5", features = ["typed-header"] }
# OPENAPI
utoipa-scalar = { version = "0.3.0", features = ["axum"] }
utoipa = "5.5.0"
utoipa = "5.4.0"
# SER/DE
ipnetwork = { version = "0.21.1", features = ["serde"] }
indexmap = { version = "2.14.0", features = ["serde"] }
indexmap = { version = "2.13.0", features = ["serde"] }
serde = { version = "1.0.227", features = ["derive"] }
strum = { version = "0.28.0", features = ["derive"] }
bson = { version = "2.15.0" } # must keep in sync with mongodb version
@@ -89,34 +91,34 @@ thiserror = "2.0.18"
tracing = "0.1.44"
# CONFIG
clap = { version = "4.6.1", features = ["derive"] }
clap = { version = "4.5.60", features = ["derive"] }
dotenvy = "0.15.7"
envy = "0.4.2"
# CRYPTO / AUTH
uuid = { version = "1.23.1", features = ["v4", "fast-rng", "serde"] }
rustls = { version = "0.23.40", features = ["aws-lc-rs"] }
uuid = { version = "1.23.0", features = ["v4", "fast-rng", "serde"] }
rustls = { version = "0.23.37", features = ["aws-lc-rs"] }
data-encoding = "2.10.0"
urlencoding = "2.1.3"
bcrypt = "0.19.0"
hmac = "0.13.0"
sha1 = "0.11.0"
sha2 = "0.11.0"
rand = "0.10.1"
hmac = "0.12.1"
sha1 = "0.10.6"
sha2 = "0.10.9"
rand = "0.10.0"
hex = "0.4.3"
# SYSTEM
hickory-resolver = "0.26.1"
hickory-resolver = "0.25.2"
portable-pty = "0.9.0"
shell-escape = "0.1.5"
crossterm = "0.29.0"
bollard = "0.21.0"
bollard = "0.20.2"
sysinfo = "0.38.4"
shlex = "1.3.0"
# CLOUD
aws-config = "1.8.16"
aws-sdk-ec2 = "1.224.0"
aws-config = "1.8.15"
aws-sdk-ec2 = "1.220.1"
aws-credential-types = "1.2.14"
## CRON
@@ -126,8 +128,7 @@ chrono = "0.4.44"
croner = "3.0.1"
# MISC
async-compression = { version = "0.4.42", features = ["tokio", "gzip"] }
schemars = { version = "1.2.1", features = ["indexmap2"] }
async-compression = { version = "0.4.41", features = ["tokio", "gzip"] }
derive_builder = "0.20.2"
comfy-table = "7.2.2"
typeshare = "1.0.5"
@@ -135,6 +136,3 @@ wildcard = "0.3.0"
colored = "3.1.1"
bytes = "1.11.1"
regex = "1.12.3"
[profile.release]
strip = "debuginfo"
+1 -2
View File
@@ -1,7 +1,7 @@
## Builds the Komodo Core, Periphery, and Util binaries
## for a specific architecture. Requires OpenSSL 3 or later.
FROM rust:1.95.0-bookworm AS builder
FROM rust:1.94.1-bookworm AS builder
RUN cargo install cargo-strip
WORKDIR /builder
@@ -12,7 +12,6 @@ COPY ./client/periphery ./client/periphery
COPY ./bin/core ./bin/core
COPY ./bin/periphery ./bin/periphery
COPY ./bin/cli ./bin/cli
COPY ./xtask ./xtask
# Compile bin
RUN \
+1 -1
View File
@@ -3,7 +3,7 @@
## Uses chef for dependency caching to help speed up back-to-back builds.
FROM lukemathwalker/cargo-chef:latest-rust-1.95.0-bookworm AS chef
FROM lukemathwalker/cargo-chef:latest-rust-1.94.1-bookworm AS chef
WORKDIR /builder
# Plan just the RECIPE to see if things have changed
+1 -1
View File
@@ -1,4 +1,4 @@
FROM rust:1.95.0-trixie AS builder
FROM rust:1.94.1-bullseye AS builder
RUN cargo install cargo-strip
WORKDIR /builder
+1 -1
View File
@@ -9,7 +9,7 @@ ARG AARCH64_BINARIES=${BINARIES_IMAGE}-aarch64
FROM ${X86_64_BINARIES} AS x86_64
FROM ${AARCH64_BINARIES} AS aarch64
FROM debian:trixie-slim
FROM debian:bullseye-slim
WORKDIR /app
+2 -4
View File
@@ -1,7 +1,7 @@
## All in one, multi stage compile + runtime Docker build for your architecture.
# Build Core
FROM rust:1.95.0-trixie AS core-builder
FROM rust:1.94.1-trixie AS core-builder
RUN cargo install cargo-strip
WORKDIR /builder
@@ -11,7 +11,6 @@ COPY ./client/core/rs ./client/core/rs
COPY ./client/periphery ./client/periphery
COPY ./bin/core ./bin/core
COPY ./bin/cli ./bin/cli
COPY ./xtask ./xtask
# Compile app
RUN cargo build -p komodo_core --release && \
@@ -59,8 +58,7 @@ ENV KOMODO_CLI_CONFIG_PATHS="/config"
# This ensures any `komodo.cli.*` takes precedence over the Core `/config/*config.*`
ENV KOMODO_CLI_CONFIG_KEYWORDS="*config.*,*komodo.cli*.*"
ENTRYPOINT [ "entrypoint.sh" ]
CMD [ "core" ]
CMD [ "/bin/bash", "-c", "update-ca-certificates && core" ]
# Label to prevent Komodo from stopping with StopAllContainers
LABEL komodo.skip="true"
+158
View File
@@ -0,0 +1,158 @@
use std::time::Instant;
use axum::{Router, extract::Path, http::HeaderMap, routing::post};
use derive_variants::{EnumVariants, ExtractVariant};
use komodo_client::{api::auth::*, entities::user::User};
use reqwest::StatusCode;
use resolver_api::Resolve;
use response::Response;
use serde::{Deserialize, Serialize};
use serde_json::json;
use serror::{AddStatusCode, Json};
use typeshare::typeshare;
use uuid::Uuid;
use crate::{
auth::{
get_user_id_from_headers,
github::{self, client::github_oauth_client},
google::{self, client::google_oauth_client},
oidc::{self, client::oidc_client},
},
config::core_config,
helpers::query::get_user,
state::jwt_client,
};
use super::Variant;
#[derive(Default)]
pub struct AuthArgs {
pub headers: HeaderMap,
}
#[typeshare]
#[derive(
Serialize, Deserialize, Debug, Clone, Resolve, EnumVariants,
)]
#[args(AuthArgs)]
#[response(Response)]
#[error(serror::Error)]
#[variant_derive(Debug)]
#[serde(tag = "type", content = "params")]
#[allow(clippy::enum_variant_names, clippy::large_enum_variant)]
pub enum AuthRequest {
GetLoginOptions(GetLoginOptions),
SignUpLocalUser(SignUpLocalUser),
LoginLocalUser(LoginLocalUser),
ExchangeForJwt(ExchangeForJwt),
GetUser(GetUser),
}
pub fn router() -> Router {
let mut router = Router::new()
.route("/", post(handler))
.route("/{variant}", post(variant_handler));
if core_config().local_auth {
info!("🔑 Local Login Enabled");
}
if github_oauth_client().is_some() {
info!("🔑 Github Login Enabled");
router = router.nest("/github", github::router())
}
if google_oauth_client().is_some() {
info!("🔑 Google Login Enabled");
router = router.nest("/google", google::router())
}
if core_config().oidc_enabled {
info!("🔑 OIDC Login Enabled");
router = router.nest("/oidc", oidc::router())
}
router
}
async fn variant_handler(
headers: HeaderMap,
Path(Variant { variant }): Path<Variant>,
Json(params): Json<serde_json::Value>,
) -> serror::Result<axum::response::Response> {
let req: AuthRequest = serde_json::from_value(json!({
"type": variant,
"params": params,
}))?;
handler(headers, Json(req)).await
}
#[instrument(name = "AuthHandler", level = "debug", skip(headers))]
async fn handler(
headers: HeaderMap,
Json(request): Json<AuthRequest>,
) -> serror::Result<axum::response::Response> {
let timer = Instant::now();
let req_id = Uuid::new_v4();
debug!(
"/auth request {req_id} | METHOD: {:?}",
request.extract_variant()
);
let res = request.resolve(&AuthArgs { headers }).await;
if let Err(e) = &res {
debug!("/auth request {req_id} | error: {:#}", e.error);
}
let elapsed = timer.elapsed();
debug!("/auth request {req_id} | resolve time: {elapsed:?}");
res.map(|res| res.0)
}
fn login_options_response() -> GetLoginOptionsResponse {
let config = core_config();
GetLoginOptionsResponse {
local: config.local_auth,
github: github_oauth_client().is_some(),
google: google_oauth_client().is_some(),
oidc: oidc_client().load().is_some(),
registration_disabled: config.disable_user_registration,
}
}
impl Resolve<AuthArgs> for GetLoginOptions {
#[instrument(name = "GetLoginOptions", level = "debug", skip(self))]
async fn resolve(
self,
_: &AuthArgs,
) -> serror::Result<GetLoginOptionsResponse> {
Ok(login_options_response())
}
}
impl Resolve<AuthArgs> for ExchangeForJwt {
#[instrument(name = "ExchangeForJwt", level = "debug", skip(self))]
async fn resolve(
self,
_: &AuthArgs,
) -> serror::Result<ExchangeForJwtResponse> {
jwt_client()
.redeem_exchange_token(&self.token)
.await
.map_err(Into::into)
}
}
impl Resolve<AuthArgs> for GetUser {
#[instrument(name = "GetUser", level = "debug", skip(self))]
async fn resolve(
self,
AuthArgs { headers }: &AuthArgs,
) -> serror::Result<User> {
let user_id = get_user_id_from_headers(headers)
.await
.status_code(StatusCode::UNAUTHORIZED)?;
get_user(&user_id)
.await
.status_code(StatusCode::UNAUTHORIZED)
}
}
+4 -4
View File
@@ -509,10 +509,10 @@ pub async fn validate_cancel_build(
)?;
match (latest_build, latest_cancel) {
(Some(build), Some(cancel))
if cancel.start_ts > build.start_ts =>
{
return Err(anyhow!("Build has already been cancelled"));
(Some(build), Some(cancel)) => {
if cancel.start_ts > build.start_ts {
return Err(anyhow!("Build has already been cancelled"));
}
}
(None, _) => return Err(anyhow!("No build in progress")),
_ => {}
+6 -5
View File
@@ -698,12 +698,13 @@ pub async fn validate_cancel_repo_build(
)?;
match (latest_build, latest_cancel) {
(Some(build), Some(cancel))
if cancel.start_ts > build.start_ts =>
{
return Err(anyhow!("Repo build has already been cancelled"));
(Some(build), Some(cancel)) => {
if cancel.start_ts > build.start_ts {
return Err(anyhow!(
"Repo build has already been cancelled"
));
}
}
(None, _) => return Err(anyhow!("No repo build in progress")),
_ => {}
};
+15 -18
View File
@@ -283,7 +283,6 @@ impl Resolve<ExecuteArgs> for RunSync {
Default::default()
};
// New resource types need to be added here manually.
if deploy_cache.is_empty()
&& resource_sync_deltas.no_changes()
&& server_deltas.no_changes()
@@ -340,7 +339,10 @@ impl Resolve<ExecuteArgs> for RunSync {
)
.await,
);
maybe_extend(
&mut update.logs,
ResourceSync::execute_sync_updates(resource_sync_deltas).await,
);
maybe_extend(
&mut update.logs,
Server::execute_sync_updates(server_deltas).await,
@@ -354,43 +356,38 @@ impl Resolve<ExecuteArgs> for RunSync {
Action::execute_sync_updates(action_deltas).await,
);
// Depends on server
// Dependent on server
maybe_extend(
&mut update.logs,
Swarm::execute_sync_updates(swarm_deltas).await,
);
// Depends on server
maybe_extend(
&mut update.logs,
Builder::execute_sync_updates(builder_deltas).await,
);
// Depends on server / builder
maybe_extend(
&mut update.logs,
Repo::execute_sync_updates(repo_deltas).await,
);
// Depends on builder / repo
// Dependant on builder
maybe_extend(
&mut update.logs,
Build::execute_sync_updates(build_deltas).await,
);
// Depends on server / repo
maybe_extend(
&mut update.logs,
Stack::execute_sync_updates(stack_deltas).await,
);
// Depends on repo
maybe_extend(
&mut update.logs,
ResourceSync::execute_sync_updates(resource_sync_deltas).await,
);
// Depends on server / build
// Dependant on server / build
maybe_extend(
&mut update.logs,
Deployment::execute_sync_updates(deployment_deltas).await,
);
// Depends on everything
// stack only depends on server, but maybe will depend on build later.
maybe_extend(
&mut update.logs,
Stack::execute_sync_updates(stack_deltas).await,
);
// Dependant on everything
maybe_extend(
&mut update.logs,
Procedure::execute_sync_updates(procedure_deltas).await,
@@ -1,7 +1,7 @@
use anyhow::{Context, anyhow};
use axum::http::HeaderMap;
use hex::ToHex;
use hmac::{Hmac, KeyInit as _, Mac};
use hmac::{Hmac, Mac};
use serde::Deserialize;
use sha2::Sha256;
+3 -10
View File
@@ -555,9 +555,8 @@ impl Resolve<WriteArgs> for RefreshStackCache {
&mut services,
) {
warn!(
stack = stack.id,
stack_name = stack.name,
"Failed to extract stack services | {e:#}",
"failed to extract stack services, things won't works correctly. stack: {} | {e:#}",
stack.name
);
}
}
@@ -776,13 +775,7 @@ pub async fn check_stack_for_update_inner(
if image.is_empty() ||
// Images with a hardcoded digest can't have update.
image.contains('@') ||
// Services explicitly excluded from global auto-update checks.
// Manual checks should still evaluate all services.
(wait_for_auto_update &&
stack.config.auto_update_skip_services.contains(
&service.service_name,
))
image.contains('@')
{
service.image_digest = None;
continue;
-15
View File
@@ -205,20 +205,6 @@ impl AuthImpl for KomodoAuthImpl {
core_config().disable_user_registration
}
fn local_registration_disabled(&self) -> bool {
let config = core_config();
config
.disable_local_user_registration
.unwrap_or(config.disable_user_registration)
}
fn oidc_registration_disabled(&self) -> bool {
let config = core_config();
config
.disable_oidc_user_registration
.unwrap_or(config.disable_user_registration)
}
fn validate_username(
&self,
username: &str,
@@ -362,7 +348,6 @@ impl AuthImpl for KomodoAuthImpl {
additional_audiences: config
.oidc_additional_audiences
.clone(),
auto_redirect: config.oidc_auto_redirect,
}
});
Some(&OIDC_CONFIG)
-24
View File
@@ -235,9 +235,6 @@ pub fn core_config() -> &'static CoreConfig {
env.komodo_oidc_additional_audiences,
)
.unwrap_or(config.oidc_additional_audiences),
oidc_auto_redirect: env
.komodo_oidc_auto_redirect
.unwrap_or(config.oidc_auto_redirect),
google_oauth: NamedOauthConfig {
enabled: env
.komodo_google_oauth_enabled
@@ -315,21 +312,6 @@ pub fn core_config() -> &'static CoreConfig {
session_allow_cross_site: env
.komodo_session_allow_cross_site
.unwrap_or(config.session_allow_cross_site),
x_content_type_options: env
.komodo_x_content_type_options
.unwrap_or(config.x_content_type_options),
x_frame_options: env
.komodo_x_frame_options
.unwrap_or(config.x_frame_options),
x_xss_protection: env
.komodo_x_xss_protection
.unwrap_or(config.x_xss_protection),
referrer_policy: env
.komodo_referrer_policy
.unwrap_or(config.referrer_policy),
content_security_policy: env
.komodo_content_security_policy
.unwrap_or(config.content_security_policy),
resource_poll_interval: env
.komodo_resource_poll_interval
.unwrap_or(config.resource_poll_interval),
@@ -363,12 +345,6 @@ pub fn core_config() -> &'static CoreConfig {
disable_user_registration: env
.komodo_disable_user_registration
.unwrap_or(config.disable_user_registration),
disable_local_user_registration: env
.komodo_disable_local_user_registration
.or(config.disable_local_user_registration),
disable_oidc_user_registration: env
.komodo_disable_oidc_user_registration
.or(config.disable_oidc_user_registration),
disable_non_admin_create: env
.komodo_disable_non_admin_create
.unwrap_or(config.disable_non_admin_create),
+12 -22
View File
@@ -38,6 +38,8 @@ pub fn extract_services_into_res(
"failed to parse service names from compose contents",
)?;
let mut services = Vec::with_capacity(compose.services.capacity());
for (
service_name,
ComposeService {
@@ -47,29 +49,17 @@ pub fn extract_services_into_res(
},
) in compose.services
{
if let Some(existing) =
res.iter_mut().find(|s| s.service_name == service_name)
{
// Override any defined fields
if let Some(container_name) = container_name {
existing.container_name = container_name;
}
if let Some(image) = image {
existing.image = image;
}
} else {
res.push(StackServiceNames {
container_name: container_name.unwrap_or_else(|| {
format!("{project_name}-{service_name}")
}),
image_digest: service_image_digests
.get(&service_name)
.cloned(),
image: image.unwrap_or_default(),
service_name,
});
}
let image = image.unwrap_or_default();
services.push(StackServiceNames {
container_name: container_name
.unwrap_or_else(|| format!("{project_name}-{service_name}")),
image_digest: service_image_digests.get(&service_name).cloned(),
service_name,
image,
});
}
res.extend(services);
Ok(())
}
-35
View File
@@ -458,41 +458,6 @@ impl ToToml for Builder {
toml.push_str("\nparams = {}");
}
}
fn edit_config_object(
_resource: &ResourceToml<Self::PartialConfig>,
config: IndexMap<String, serde_json::Value>,
) -> anyhow::Result<IndexMap<String, serde_json::Value>> {
config
.into_iter()
.map(|(key, value)| {
#[allow(clippy::single_match)]
match key.as_str() {
"params" => match value {
serde_json::Value::Object(obj) => Ok((
key,
serde_json::Value::Object(
obj
.into_iter()
.map(|(key, value)| {
match key.as_str() {
"server_id" => {
return (String::from("server"), value);
}
_ => {}
}
(key, value)
})
.collect(),
),
)),
value => Ok((key, value)),
},
_ => Ok((key, value)),
}
})
.collect()
}
}
impl ToToml for Procedure {
+1 -2
View File
@@ -1,6 +1,6 @@
## All in one, multi stage compile + runtime Docker build for your architecture.
FROM rust:1.95.0-trixie AS builder
FROM rust:1.94.1-trixie AS builder
RUN cargo install cargo-strip
WORKDIR /builder
@@ -9,7 +9,6 @@ COPY ./lib ./lib
COPY ./client/core/rs ./client/core/rs
COPY ./client/periphery ./client/periphery
COPY ./bin/periphery ./bin/periphery
COPY ./xtask ./xtask
# Compile app
RUN cargo build -p komodo_periphery --release && cargo strip
+1 -5
View File
@@ -271,11 +271,7 @@ impl Resolve<crate::api::Args> for build::Build {
"Pre Build",
pre_build_path.as_path(),
&pre_build.command,
if pre_build.shell_mode {
KomodoCommandMode::Shell
} else {
KomodoCommandMode::Multiline
},
KomodoCommandMode::Multiline,
&replacers,
)
.instrument(span)
+2 -10
View File
@@ -490,11 +490,7 @@ impl Resolve<crate::api::Args> for ComposeUp {
"Pre Deploy",
pre_deploy_path.as_path(),
&stack.config.pre_deploy.command,
if stack.config.pre_deploy.shell_mode {
KomodoCommandMode::Shell
} else {
KomodoCommandMode::Multiline
},
KomodoCommandMode::Multiline,
&replacers,
)
.instrument(span)
@@ -764,11 +760,7 @@ impl Resolve<crate::api::Args> for ComposeUp {
"Post Deploy",
post_deploy_path.as_path(),
&stack.config.post_deploy.command,
if stack.config.post_deploy.shell_mode {
KomodoCommandMode::Shell
} else {
KomodoCommandMode::Multiline
},
KomodoCommandMode::Multiline,
&replacers,
)
.instrument(span)
+5 -8
View File
@@ -10,7 +10,7 @@ use crate::state::container_stats;
use super::{
DockerClient, convert_health_config, convert_mount,
convert_resources_ulimits,
convert_mount_point_type, convert_resources_ulimits,
};
impl DockerClient {
@@ -360,7 +360,10 @@ impl DockerClient {
.unwrap_or_default()
.into_iter()
.map(|mount| MountPoint {
typ: mount.typ,
typ: mount
.typ
.map(convert_mount_point_type)
.unwrap_or_default(),
name: mount.name,
source: mount.source,
destination: mount.destination,
@@ -479,9 +482,6 @@ fn convert_summary_container_state(
bollard::config::ContainerSummaryStateEnum::EXITED => {
ContainerStateStatusEnum::Exited
}
bollard::config::ContainerSummaryStateEnum::STOPPING => {
ContainerStateStatusEnum::Stopping
}
bollard::config::ContainerSummaryStateEnum::REMOVING => {
ContainerStateStatusEnum::Removing
}
@@ -516,9 +516,6 @@ fn convert_container_state_status(
bollard::config::ContainerStateStatusEnum::REMOVING => {
ContainerStateStatusEnum::Removing
}
bollard::config::ContainerStateStatusEnum::STOPPING => {
ContainerStateStatusEnum::Stopping
}
bollard::config::ContainerStateStatusEnum::DEAD => {
ContainerStateStatusEnum::Dead
}
+36 -7
View File
@@ -150,14 +150,17 @@ fn convert_mount(mount: bollard::models::Mount) -> Mount {
}
}
fn convert_mount_type(typ: bollard::config::MountType) -> MountType {
fn convert_mount_type(
typ: bollard::config::MountTypeEnum,
) -> MountTypeEnum {
match typ {
bollard::config::MountType::BIND => MountType::Bind,
bollard::config::MountType::VOLUME => MountType::Volume,
bollard::config::MountType::IMAGE => MountType::Image,
bollard::config::MountType::TMPFS => MountType::Tmpfs,
bollard::config::MountType::NPIPE => MountType::Npipe,
bollard::config::MountType::CLUSTER => MountType::Cluster,
bollard::config::MountTypeEnum::EMPTY => MountTypeEnum::Empty,
bollard::config::MountTypeEnum::BIND => MountTypeEnum::Bind,
bollard::config::MountTypeEnum::VOLUME => MountTypeEnum::Volume,
bollard::config::MountTypeEnum::IMAGE => MountTypeEnum::Image,
bollard::config::MountTypeEnum::TMPFS => MountTypeEnum::Tmpfs,
bollard::config::MountTypeEnum::NPIPE => MountTypeEnum::Npipe,
bollard::config::MountTypeEnum::CLUSTER => MountTypeEnum::Cluster,
}
}
@@ -189,6 +192,32 @@ fn convert_mount_propogation(
}
}
fn convert_mount_point_type(
typ: bollard::config::MountPointTypeEnum,
) -> MountTypeEnum {
match typ {
bollard::config::MountPointTypeEnum::EMPTY => {
MountTypeEnum::Empty
}
bollard::config::MountPointTypeEnum::BIND => MountTypeEnum::Bind,
bollard::config::MountPointTypeEnum::VOLUME => {
MountTypeEnum::Volume
}
bollard::config::MountPointTypeEnum::IMAGE => {
MountTypeEnum::Image
}
bollard::config::MountPointTypeEnum::TMPFS => {
MountTypeEnum::Tmpfs
}
bollard::config::MountPointTypeEnum::NPIPE => {
MountTypeEnum::Npipe
}
bollard::config::MountPointTypeEnum::CLUSTER => {
MountTypeEnum::Cluster
}
}
}
fn convert_health_config(
config: bollard::models::HealthConfig,
) -> HealthConfig {
+4 -4
View File
@@ -1,6 +1,6 @@
use bollard::query_parameters::ListVolumesOptions;
use komodo_client::entities::docker::{
Topology, container::ContainerListItem, volume::*,
PortBinding, container::ContainerListItem, volume::*,
};
use crate::docker::DockerClient;
@@ -108,8 +108,8 @@ impl DockerClient {
}).collect(),
accessibility_requirements: mode
.accessibility_requirements.map(|req| ClusterVolumeSpecAccessModeAccessibilityRequirements {
requisite: req.requisite.map(|v| v.into_iter().map(|t| Topology { segments: t.segments }).collect()),
preferred: req.preferred.map(|v| v.into_iter().map(|t| Topology { segments: t.segments }).collect()),
requisite: req.requisite.unwrap_or_default().into_iter().map(|map| map.into_iter().map(|(k, v)| (k, v.unwrap_or_default().into_iter().map(|p| PortBinding { host_ip: p.host_ip, host_port: p.host_port }).collect())).collect()).collect(),
preferred: req.preferred.unwrap_or_default().into_iter().map(|map| map.into_iter().map(|(k, v)| (k, v.unwrap_or_default().into_iter().map(|p| PortBinding { host_ip: p.host_ip, host_port: p.host_port }).collect())).collect()).collect(),
}),
capacity_range: mode.capacity_range.map(|range| ClusterVolumeSpecAccessModeCapacityRange {
required_bytes: range.required_bytes,
@@ -128,7 +128,7 @@ impl DockerClient {
capacity_bytes: info.capacity_bytes,
volume_context: info.volume_context.unwrap_or_default(),
volume_id: info.volume_id,
accessible_topology: info.accessible_topology.map(|v| v.into_iter().map(|t| Topology { segments: t.segments }).collect()),
accessible_topology: info.accessible_topology.unwrap_or_default().into_iter().map(|map| map.into_iter().map(|(k, v)| (k, v.unwrap_or_default().into_iter().map(|p| PortBinding { host_ip: p.host_ip, host_port: p.host_port }).collect())).collect()).collect(),
}),
publish_status: volume
.publish_status
+19 -21
View File
@@ -189,11 +189,7 @@ pub async fn handle_post_repo_execution(
"On Clone",
path.as_path(),
on_clone.command,
if on_clone.shell_mode {
KomodoCommandMode::Shell
} else {
KomodoCommandMode::Multiline
},
KomodoCommandMode::Multiline,
&replacers,
)
.await
@@ -218,11 +214,7 @@ pub async fn handle_post_repo_execution(
"On Pull",
path.as_path(),
on_pull.command,
if on_pull.shell_mode {
KomodoCommandMode::Shell
} else {
KomodoCommandMode::Multiline
},
KomodoCommandMode::Multiline,
&replacers,
)
.await
@@ -284,31 +276,37 @@ pub fn registry_token(
// Public IP over DNS
// ====================
type OpenDNSResolver = hickory_resolver::TokioResolver;
type OpenDNSResolver = hickory_resolver::Resolver<
hickory_resolver::name_server::TokioConnectionProvider,
>;
fn opendns_resolver() -> &'static OpenDNSResolver {
static OPENDNS_RESOLVER: OnceLock<OpenDNSResolver> =
OnceLock::new();
OPENDNS_RESOLVER.get_or_init(|| {
// OpenDNS resolver ipv4s.
let name_servers = [
// OpenDNS resolver ipv4s
let ips = [
IpAddr::from_str("208.67.220.220").unwrap(),
IpAddr::from_str("208.67.222.222").unwrap(),
]
.into_iter()
.map(hickory_resolver::config::NameServerConfig::udp_and_tcp)
.collect();
];
// trust_negative_responses=true means NXDOMAIN/empty NOERROR from an
// authoritative upstream wont be retried on other servers.
let ns =
hickory_resolver::config::NameServerConfigGroup::from_ips_clear(
&ips, 53, true,
);
hickory_resolver::Resolver::builder_with_config(
hickory_resolver::config::ResolverConfig::from_parts(
None,
vec![],
name_servers,
ns,
),
hickory_resolver::name_server::TokioConnectionProvider::default(
),
hickory_resolver::net::runtime::TokioRuntimeProvider::default(),
)
.build()
.expect("Failed to build OpenDNS resolver")
})
}
@@ -321,7 +319,7 @@ pub async fn resolve_host_public_ip() -> anyhow::Result<String> {
.context(
"Failed to query OpenDNS resolvers for host public IP",
)?
.iter()
.into_iter()
.map(|ip| ip.to_string())
.next()
.context("OpenDNS call for public IP didn't return anything")
-2
View File
@@ -14,7 +14,6 @@ repository.workspace = true
blocking = ["reqwest/blocking"]
mongo = ["dep:mongo_indexed"]
utoipa = ["dep:utoipa", "mogh_auth_client/utoipa", "mogh_error/utoipa"]
schemars = ["dep:schemars"]
logger = ["dep:mogh_logger"]
cli = ["logger", "dep:mogh_pki",]
core = ["mongo", "utoipa", "logger", "dep:mogh_server"]
@@ -34,7 +33,6 @@ partial_derive2.workspace = true
mogh_resolver.workspace = true
# external
ipnetwork = { workspace = true, optional = true }
schemars = { workspace = true, optional = true }
utoipa = { workspace = true, optional = true }
tokio-tungstenite.workspace = true
derive_builder.workspace = true
-2
View File
@@ -28,7 +28,6 @@ pub fn run_action() {}
Debug, Clone, PartialEq, Serialize, Deserialize, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -69,7 +68,6 @@ pub fn batch_run_action() {}
Debug, Clone, PartialEq, Serialize, Deserialize, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(BatchExecutionResponse)]
#[error(mogh_error::Error)]
@@ -27,7 +27,6 @@ pub fn test_alerter() {}
Serialize, Deserialize, Debug, Clone, PartialEq, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -57,7 +56,6 @@ pub fn send_alert() {}
Serialize, Deserialize, Debug, Clone, PartialEq, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
-3
View File
@@ -39,7 +39,6 @@ pub fn run_build() {}
Debug, Clone, PartialEq, Serialize, Deserialize, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -68,7 +67,6 @@ pub fn batch_run_build() {}
Debug, Clone, PartialEq, Serialize, Deserialize, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(BatchExecutionResponse)]
#[error(mogh_error::Error)]
@@ -108,7 +106,6 @@ pub fn cancel_build() {}
Serialize, Deserialize, Debug, Clone, PartialEq, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -34,7 +34,6 @@ pub fn deploy() {}
Serialize, Deserialize, Debug, Clone, PartialEq, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -69,7 +68,6 @@ pub fn batch_deploy() {}
Serialize, Deserialize, Debug, Clone, PartialEq, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(BatchExecutionResponse)]
#[error(mogh_error::Error)]
@@ -107,7 +105,6 @@ pub fn pull_deployment() {}
Serialize, Deserialize, Debug, Clone, PartialEq, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -138,7 +135,6 @@ pub fn start_deployment() {}
Serialize, Deserialize, Debug, Clone, PartialEq, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -169,7 +165,6 @@ pub fn restart_deployment() {}
Serialize, Deserialize, Debug, Clone, PartialEq, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -200,7 +195,6 @@ pub fn pause_deployment() {}
Serialize, Deserialize, Debug, Clone, PartialEq, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -234,7 +228,6 @@ pub fn unpause_deployment() {}
Serialize, Deserialize, Debug, Clone, PartialEq, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -265,7 +258,6 @@ pub fn stop_deployment() {}
Serialize, Deserialize, Debug, Clone, PartialEq, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -303,7 +295,6 @@ pub fn destroy_deployment() {}
Serialize, Deserialize, Debug, Clone, PartialEq, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -336,7 +327,6 @@ pub fn batch_destroy_deployment() {}
Serialize, Deserialize, Debug, Clone, PartialEq, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(BatchExecutionResponse)]
#[error(mogh_error::Error)]
@@ -28,7 +28,6 @@ pub fn clear_repo_cache() {}
Debug, Clone, PartialEq, Serialize, Deserialize, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -61,7 +60,6 @@ pub fn backup_core_database() {}
Debug, Clone, PartialEq, Serialize, Deserialize, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -94,7 +92,6 @@ pub fn global_auto_update() {}
Debug, Clone, PartialEq, Serialize, Deserialize, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -128,7 +125,6 @@ pub fn rotate_all_server_keys() {}
Debug, Clone, PartialEq, Serialize, Deserialize, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -159,7 +155,6 @@ pub fn rotate_core_keys() {}
Debug, Clone, PartialEq, Serialize, Deserialize, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
-2
View File
@@ -78,7 +78,6 @@ pub trait KomodoExecuteRequest: HasResponse {}
utoipa::ToSchema
))
)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[serde(tag = "type", content = "params")]
pub enum Execution {
/// The "null" execution. Does nothing.
@@ -216,7 +215,6 @@ pub enum Execution {
#[typeshare]
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Parser)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct Sleep {
#[serde(default)]
pub duration_ms: I64,
@@ -27,7 +27,6 @@ pub fn run_procedure() {}
Debug, Clone, PartialEq, Serialize, Deserialize, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -56,7 +55,6 @@ pub fn batch_run_procedure() {}
Debug, Clone, PartialEq, Serialize, Deserialize, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(BatchExecutionResponse)]
#[error(mogh_error::Error)]
-7
View File
@@ -35,7 +35,6 @@ pub fn clone_repo() {}
Serialize, Deserialize, Debug, Clone, PartialEq, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -64,7 +63,6 @@ pub fn batch_clone_repo() {}
Debug, Clone, PartialEq, Serialize, Deserialize, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(BatchExecutionResponse)]
#[error(mogh_error::Error)]
@@ -107,7 +105,6 @@ pub fn pull_repo() {}
Serialize, Deserialize, Debug, Clone, PartialEq, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -136,7 +133,6 @@ pub fn batch_pull_repo() {}
Debug, Clone, PartialEq, Serialize, Deserialize, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(BatchExecutionResponse)]
#[error(mogh_error::Error)]
@@ -183,7 +179,6 @@ pub fn build_repo() {}
Serialize, Deserialize, Debug, Clone, PartialEq, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -212,7 +207,6 @@ pub fn batch_build_repo() {}
Debug, Clone, PartialEq, Serialize, Deserialize, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(BatchExecutionResponse)]
#[error(mogh_error::Error)]
@@ -252,7 +246,6 @@ pub fn cancel_repo_build() {}
Serialize, Deserialize, Debug, Clone, PartialEq, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
-21
View File
@@ -31,7 +31,6 @@ pub fn start_container() {}
Serialize, Deserialize, Debug, Clone, PartialEq, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -64,7 +63,6 @@ pub fn restart_container() {}
Serialize, Deserialize, Debug, Clone, PartialEq, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -97,7 +95,6 @@ pub fn pause_container() {}
Serialize, Deserialize, Debug, Clone, PartialEq, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -132,7 +129,6 @@ pub fn unpause_container() {}
Serialize, Deserialize, Debug, Clone, PartialEq, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -165,7 +161,6 @@ pub fn stop_container() {}
Serialize, Deserialize, Debug, Clone, PartialEq, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -203,7 +198,6 @@ pub fn destroy_container() {}
Serialize, Deserialize, Debug, Clone, PartialEq, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -238,7 +232,6 @@ pub fn start_all_containers() {}
Serialize, Deserialize, Debug, Clone, PartialEq, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -267,7 +260,6 @@ pub fn restart_all_containers() {}
Serialize, Deserialize, Debug, Clone, PartialEq, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -296,7 +288,6 @@ pub fn pause_all_containers() {}
Serialize, Deserialize, Debug, Clone, PartialEq, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -325,7 +316,6 @@ pub fn unpause_all_containers() {}
Serialize, Deserialize, Debug, Clone, PartialEq, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -354,7 +344,6 @@ pub fn stop_all_containers() {}
Serialize, Deserialize, Debug, Clone, PartialEq, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -385,7 +374,6 @@ pub fn prune_containers() {}
Serialize, Deserialize, Debug, Clone, PartialEq, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -417,7 +405,6 @@ pub fn delete_network() {}
Serialize, Deserialize, Debug, Clone, PartialEq, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -450,7 +437,6 @@ pub fn prune_networks() {}
Serialize, Deserialize, Debug, Clone, PartialEq, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -480,7 +466,6 @@ pub fn delete_image() {}
Serialize, Deserialize, Debug, Clone, PartialEq, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -513,7 +498,6 @@ pub fn prune_images() {}
Serialize, Deserialize, Debug, Clone, PartialEq, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -543,7 +527,6 @@ pub fn delete_volume() {}
Serialize, Deserialize, Debug, Clone, PartialEq, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -576,7 +559,6 @@ pub fn prune_volumes() {}
Serialize, Deserialize, Debug, Clone, PartialEq, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -607,7 +589,6 @@ pub fn prune_docker_builders() {}
Serialize, Deserialize, Debug, Clone, PartialEq, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -638,7 +619,6 @@ pub fn prune_buildx() {}
Serialize, Deserialize, Debug, Clone, PartialEq, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -669,7 +649,6 @@ pub fn prune_system() {}
Serialize, Deserialize, Debug, Clone, PartialEq, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
-14
View File
@@ -27,7 +27,6 @@ pub fn deploy_stack() {}
Debug, Clone, PartialEq, Serialize, Deserialize, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -65,7 +64,6 @@ pub fn batch_deploy_stack() {}
Serialize, Deserialize, Debug, Clone, PartialEq, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(BatchExecutionResponse)]
#[error(mogh_error::Error)]
@@ -105,7 +103,6 @@ pub fn deploy_stack_if_changed() {}
Debug, Clone, PartialEq, Serialize, Deserialize, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -137,7 +134,6 @@ pub fn batch_deploy_stack_if_changed() {}
Serialize, Deserialize, Debug, Clone, PartialEq, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(BatchExecutionResponse)]
#[error(mogh_error::Error)]
@@ -175,7 +171,6 @@ pub fn pull_stack() {}
Debug, Clone, PartialEq, Serialize, Deserialize, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -208,7 +203,6 @@ pub fn batch_pull_stack() {}
Serialize, Deserialize, Debug, Clone, PartialEq, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(BatchExecutionResponse)]
#[error(mogh_error::Error)]
@@ -246,7 +240,6 @@ pub fn start_stack() {}
Debug, Clone, PartialEq, Serialize, Deserialize, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -279,7 +272,6 @@ pub fn restart_stack() {}
Debug, Clone, PartialEq, Serialize, Deserialize, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -312,7 +304,6 @@ pub fn pause_stack() {}
Debug, Clone, PartialEq, Serialize, Deserialize, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -347,7 +338,6 @@ pub fn unpause_stack() {}
Debug, Clone, PartialEq, Serialize, Deserialize, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -380,7 +370,6 @@ pub fn stop_stack() {}
Debug, Clone, PartialEq, Serialize, Deserialize, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -415,7 +404,6 @@ pub fn destroy_stack() {}
Debug, Clone, PartialEq, Serialize, Deserialize, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -453,7 +441,6 @@ pub fn run_stack_service() {}
Debug, Clone, PartialEq, Serialize, Deserialize, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -518,7 +505,6 @@ pub fn batch_destroy_stack() {}
Serialize, Deserialize, Debug, Clone, PartialEq, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(BatchExecutionResponse)]
#[error(mogh_error::Error)]
-10
View File
@@ -35,7 +35,6 @@ pub fn remove_swarm_nodes() {}
Serialize, Deserialize, Debug, Clone, PartialEq, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -70,7 +69,6 @@ pub fn update_swarm_node() {}
Serialize, Deserialize, Debug, Clone, PartialEq, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -117,7 +115,6 @@ pub fn remove_swarm_stacks() {}
Serialize, Deserialize, Debug, Clone, PartialEq, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -160,7 +157,6 @@ pub fn remove_swarm_services() {}
Serialize, Deserialize, Debug, Clone, PartialEq, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -195,7 +191,6 @@ pub fn create_swarm_config() {}
Serialize, Deserialize, Debug, Clone, PartialEq, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -245,7 +240,6 @@ pub fn rotate_swarm_config() {}
Serialize, Deserialize, Debug, Clone, PartialEq, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -280,7 +274,6 @@ pub fn remove_swarm_configs() {}
Serialize, Deserialize, Debug, Clone, PartialEq, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -315,7 +308,6 @@ pub fn create_swarm_secret() {}
Serialize, Deserialize, Debug, Clone, PartialEq, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -367,7 +359,6 @@ pub fn rotate_swarm_secret() {}
Serialize, Deserialize, Debug, Clone, PartialEq, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
@@ -402,7 +393,6 @@ pub fn remove_swarm_secrets() {}
Serialize, Deserialize, Debug, Clone, PartialEq, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
-1
View File
@@ -27,7 +27,6 @@ pub fn run_sync() {}
Debug, Clone, PartialEq, Serialize, Deserialize, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
+1 -1
View File
@@ -144,7 +144,7 @@ pub struct GetCoreInfoResponse {
pub enable_fancy_toml: bool,
/// TZ identifier Core is using, if manually set.
pub timezone: String,
/// Public key for Core / Periphery authentication.
/// Default public key allowing this Core to authenticate to Periphery agents.
pub public_key: String,
}
@@ -40,8 +40,7 @@ pub struct CreateOnboardingKey {
#[serde(default)]
pub expires: I64,
/// Optionally specify an existing private key, otherwise
/// generate fresh key. This key is not stored directly,
/// only the public key.
/// generate fresh key.
pub private_key: Option<String>,
/// Default tags to apply to Servers created using this key.
#[serde(default)]
-1
View File
@@ -242,7 +242,6 @@ pub fn commit_sync() {}
Debug, Clone, PartialEq, Serialize, Deserialize, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[empty_traits(KomodoWriteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
-4
View File
@@ -81,10 +81,6 @@ pub type _PartialActionConfig = PartialActionConfig;
#[derive(Serialize, Deserialize, Debug, Clone, Builder, Partial)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[partial_derive(Serialize, Deserialize, Debug, Clone, Default)]
#[cfg_attr(
feature = "schemars",
partial_derive(schemars::JsonSchema)
)]
#[diff_derive(Serialize, Deserialize, Debug, Clone, Default)]
#[partial(skip_serializing_none, from, diff)]
pub struct ActionConfig {
-5
View File
@@ -74,10 +74,6 @@ pub struct Alert {
utoipa::ToSchema
))
)]
#[cfg_attr(
feature = "schemars",
strum_discriminants(derive(schemars::JsonSchema))
)]
#[serde(tag = "type", content = "data")]
pub enum AlertData {
/// A null alert
@@ -386,7 +382,6 @@ impl Default for AlertDataVariant {
EnumString,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[serde(rename_all = "UPPERCASE")]
#[strum(serialize_all = "UPPERCASE")]
pub enum SeverityLevel {
-10
View File
@@ -45,10 +45,6 @@ pub type _PartialAlerterConfig = PartialAlerterConfig;
#[derive(Serialize, Deserialize, Debug, Clone, Builder, Partial)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[partial_derive(Serialize, Deserialize, Debug, Clone, Default)]
#[cfg_attr(
feature = "schemars",
partial_derive(schemars::JsonSchema)
)]
#[diff_derive(Serialize, Deserialize, Debug, Clone, Default)]
#[partial(skip_serializing_none, from, diff)]
pub struct AlerterConfig {
@@ -153,7 +149,6 @@ impl utoipa::ToSchema for PartialAlerterConfig {}
utoipa::ToSchema
))
)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[serde(tag = "type", content = "params")]
pub enum AlerterEndpoint {
/// Send alert serialized to JSON to an http endpoint.
@@ -184,7 +179,6 @@ impl Default for AlerterEndpoint {
Debug, Clone, PartialEq, Serialize, Deserialize, Builder,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct CustomAlerterEndpoint {
/// The http/s endpoint to send the POST to
#[serde(default = "default_custom_url")]
@@ -210,7 +204,6 @@ fn default_custom_url() -> String {
Debug, Clone, PartialEq, Serialize, Deserialize, Builder,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct SlackAlerterEndpoint {
/// The Slack app webhook url
#[serde(default = "default_slack_url")]
@@ -238,7 +231,6 @@ fn default_slack_url() -> String {
Debug, Clone, PartialEq, Serialize, Deserialize, Builder,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct DiscordAlerterEndpoint {
/// The Discord webhook url
#[serde(default = "default_discord_url")]
@@ -266,7 +258,6 @@ fn default_discord_url() -> String {
Debug, Clone, PartialEq, Serialize, Deserialize, Builder,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct NtfyAlerterEndpoint {
/// The ntfy topic URL
#[serde(default = "default_ntfy_url")]
@@ -297,7 +288,6 @@ fn default_ntfy_url() -> String {
Debug, Clone, PartialEq, Serialize, Deserialize, Builder,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct PushoverAlerterEndpoint {
/// The pushover URL including application and user tokens in parameters.
#[serde(default = "default_pushover_url")]
-33
View File
@@ -260,30 +260,18 @@ pub type _PartialBuildConfig = PartialBuildConfig;
#[derive(Debug, Clone, Serialize, Deserialize, Builder, Partial)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[partial_derive(Debug, Clone, Default, Serialize, Deserialize)]
#[cfg_attr(
feature = "schemars",
partial_derive(schemars::JsonSchema)
)]
#[diff_derive(Debug, Clone, Default, Serialize, Deserialize)]
#[partial(skip_serializing_none, from, diff)]
pub struct BuildConfig {
/// Which builder is used to build the image.
#[serde(default, alias = "builder")]
#[partial_attr(serde(alias = "builder"))]
#[cfg_attr(
feature = "schemars",
partial_attr(schemars(rename = "builder"))
)]
#[builder(default)]
pub builder_id: String,
/// The current version of the build.
#[serde(default)]
#[builder(default)]
#[cfg_attr(
feature = "schemars",
partial_attr(schemars(default, schema_with = "version_schema"))
)]
pub version: Version,
/// Whether to automatically increment the patch on every build.
@@ -535,26 +523,6 @@ fn default_webhook_enabled() -> bool {
true
}
#[cfg(feature = "schemars")]
fn version_schema(
_: &mut schemars::SchemaGenerator,
) -> schemars::Schema {
schemars::json_schema!({
"description": "The current version of the build.",
"anyOf": [
{
"$ref": "#/$defs/Version"
},
{
"type": "string"
},
{
"type": "null"
}
]
})
}
impl Default for BuildConfig {
fn default() -> Self {
Self {
@@ -609,7 +577,6 @@ impl utoipa::ToSchema for PartialBuildConfig {}
Debug, Clone, Default, PartialEq, Serialize, Deserialize,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct ImageRegistryConfig {
/// Specify the registry provider domain, eg `docker.io`.
/// If not provided, will not push to any registry.
+6 -16
View File
@@ -125,7 +125,6 @@ impl Default for BuilderConfig {
utoipa::ToSchema
))
)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[serde(tag = "type", content = "params")]
#[allow(clippy::large_enum_variant)]
pub enum PartialBuilderConfig {
@@ -371,10 +370,13 @@ pub type _PartialUrlBuilderConfig = PartialUrlBuilderConfig;
#[typeshare]
#[derive(Serialize, Deserialize, Debug, Clone, Builder, Partial)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[partial_derive(Serialize, Deserialize, Debug, Clone, Default)]
#[cfg_attr(
feature = "schemars",
partial_derive(schemars::JsonSchema)
not(feature = "utoipa"),
partial_derive(Serialize, Deserialize, Debug, Clone, Default)
)]
#[cfg_attr(
feature = "utoipa",
partial_derive(Serialize, Deserialize, Debug, Clone, Default,)
)]
#[diff_derive(Serialize, Deserialize, Debug, Clone, Default)]
#[partial(skip_serializing_none, from, diff)]
@@ -449,20 +451,12 @@ pub type _PartialServerBuilderConfig = PartialServerBuilderConfig;
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[partial_derive(Serialize, Deserialize, Debug, Clone, Default)]
#[cfg_attr(
feature = "schemars",
partial_derive(schemars::JsonSchema)
)]
#[diff_derive(Serialize, Deserialize, Debug, Clone, Default)]
#[partial(skip_serializing_none, from, diff)]
pub struct ServerBuilderConfig {
/// The server id of the builder
#[serde(default, alias = "server")]
#[partial_attr(serde(alias = "server"))]
#[cfg_attr(
feature = "schemars",
partial_attr(schemars(rename = "server"))
)]
pub server_id: String,
}
@@ -491,10 +485,6 @@ pub type _PartialAwsBuilderConfig = PartialAwsBuilderConfig;
#[derive(Debug, Clone, Serialize, Deserialize, Builder, Partial)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[partial_derive(Serialize, Deserialize, Debug, Clone, Default)]
#[cfg_attr(
feature = "schemars",
partial_derive(schemars::JsonSchema)
)]
#[diff_derive(Serialize, Deserialize, Debug, Clone, Default)]
#[partial(skip_serializing_none, from, diff)]
pub struct AwsBuilderConfig {
-117
View File
@@ -124,10 +124,6 @@ pub struct Env {
pub komodo_enable_new_users: Option<bool>,
/// Override `disable_user_registration`
pub komodo_disable_user_registration: Option<bool>,
/// Override `disable_local_user_registration`
pub komodo_disable_local_user_registration: Option<bool>,
/// Override `disable_oidc_user_registration`
pub komodo_disable_oidc_user_registration: Option<bool>,
/// Override `lock_login_credentials_for`
pub komodo_lock_login_credentials_for: Option<Vec<String>>,
/// Override `disable_confirm_dialog`
@@ -174,8 +170,6 @@ pub struct Env {
pub komodo_oidc_additional_audiences: Option<Vec<String>>,
/// Override `oidc_additional_audiences` from file
pub komodo_oidc_additional_audiences_file: Option<PathBuf>,
/// Override `oidc_auto_redirect`
pub komodo_oidc_auto_redirect: Option<bool>,
/// Override `google_oauth.enabled`
pub komodo_google_oauth_enabled: Option<bool>,
@@ -213,17 +207,6 @@ pub struct Env {
/// Override `session_allow_cross_site`
pub komodo_session_allow_cross_site: Option<bool>,
/// Override `x_content_type_options`
pub komodo_x_content_type_options: Option<String>,
/// Override `x_frame_options`
pub komodo_x_frame_options: Option<String>,
/// Override `x_xss_protection`
pub komodo_x_xss_protection: Option<String>,
/// Override `x_referrer_policy`
pub komodo_referrer_policy: Option<String>,
/// Override `content_security_policy`
pub komodo_content_security_policy: Option<String>,
/// Override `database.uri`
#[serde(alias = "komodo_mongo_uri")]
pub komodo_database_uri: Option<String>,
@@ -474,20 +457,6 @@ pub struct CoreConfig {
#[serde(default)]
pub disable_user_registration: bool,
/// Disable local (username/password) user registration only.
/// When set, the "Sign Up" button is hidden and local signups are blocked,
/// but OIDC and other external provider signups are still allowed.
/// If not set, falls back to `disable_user_registration`.
#[serde(default)]
pub disable_local_user_registration: Option<bool>,
/// Disable OIDC user registration only.
/// When set, new users cannot register via OIDC,
/// but local and other provider signups are still allowed.
/// If not set, falls back to `disable_user_registration`.
#[serde(default)]
pub disable_oidc_user_registration: Option<bool>,
/// List of usernames for which the update username / password
/// APIs are disabled. Used by demo to lock the 'demo' : 'demo' login.
///
@@ -556,12 +525,6 @@ pub struct CoreConfig {
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub oidc_additional_audiences: Vec<String>,
/// Automatically redirect unauthenticated users to the OIDC provider
/// instead of showing the login page.
/// Users can bypass the redirect by appending `?disableAutoLogin` to the login URL.
#[serde(default)]
pub oidc_auto_redirect: bool,
// =========
// = Oauth =
// =========
@@ -608,37 +571,6 @@ pub struct CoreConfig {
#[serde(default)]
pub session_allow_cross_site: bool,
// ====================
// = Security Headers =
// ====================
/// `X-Content-Type-Options` header value.
/// Default is `nosniff`. Set as empty string
/// to omit the header.
#[serde(default = "default_x_content_type_options")]
pub x_content_type_options: String,
/// `X-Frame-Options` header value. Return an empty string to
/// omit the header entirely and allow iframe on any origin. Use `"SAMEORIGIN"` to allow
/// same-origin embedding only. Defaults to `"DENY"`.
#[serde(default = "default_x_frame_options")]
pub x_frame_options: String,
/// `X-XSS-PROTECTION` header value. Return an empty string to
/// omit the header entirely. Default: `1; mode=block`
#[serde(default = "default_x_xss_protection")]
pub x_xss_protection: String,
/// Apply Referrer Policy directives.
/// If empty string, no header is applied.
/// Default: `strict-origin-when-cross-origin`
#[serde(default = "default_referrer_policy")]
pub referrer_policy: String,
/// Apply Content Security Policy directives.
/// If empty string, no header is applied.
/// Default: None
///
/// Example:
/// `default-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'; form-action 'self'`
#[serde(default)]
pub content_security_policy: String,
// ============
// = Webhooks =
// ============
@@ -835,22 +767,6 @@ fn default_auth_rate_limit_window_seconds() -> u64 {
15
}
fn default_x_content_type_options() -> String {
String::from("nosniff")
}
fn default_x_frame_options() -> String {
String::from("DENY")
}
fn default_x_xss_protection() -> String {
String::from("1; mode=block")
}
fn default_referrer_policy() -> String {
String::from("strict-origin-when-cross-origin")
}
fn default_sync_directory() -> PathBuf {
PathBuf::from("/syncs")
}
@@ -910,8 +826,6 @@ impl Default for CoreConfig {
transparent_mode: Default::default(),
enable_new_users: Default::default(),
disable_user_registration: Default::default(),
disable_local_user_registration: Default::default(),
disable_oidc_user_registration: Default::default(),
lock_login_credentials_for: Default::default(),
disable_non_admin_create: Default::default(),
jwt_secret: Default::default(),
@@ -923,7 +837,6 @@ impl Default for CoreConfig {
oidc_client_secret: Default::default(),
oidc_use_full_email: Default::default(),
oidc_additional_audiences: Default::default(),
oidc_auto_redirect: Default::default(),
google_oauth: Default::default(),
github_oauth: Default::default(),
auth_rate_limit_disabled: Default::default(),
@@ -934,11 +847,6 @@ impl Default for CoreConfig {
cors_allowed_origins: Default::default(),
cors_allow_credentials: Default::default(),
session_allow_cross_site: Default::default(),
x_content_type_options: default_x_content_type_options(),
x_frame_options: default_x_frame_options(),
x_xss_protection: default_x_xss_protection(),
referrer_policy: default_referrer_policy(),
content_security_policy: Default::default(),
webhook_secret: Default::default(),
webhook_base_url: Default::default(),
logging: Default::default(),
@@ -1001,10 +909,6 @@ impl CoreConfig {
enable_fancy_toml: config.enable_fancy_toml,
enable_new_users: config.enable_new_users,
disable_user_registration: config.disable_user_registration,
disable_local_user_registration: config
.disable_local_user_registration,
disable_oidc_user_registration: config
.disable_oidc_user_registration,
disable_non_admin_create: config.disable_non_admin_create,
lock_login_credentials_for: config.lock_login_credentials_for,
local_auth: config.local_auth,
@@ -1028,7 +932,6 @@ impl CoreConfig {
.iter()
.map(|aud| empty_or_redacted(aud))
.collect(),
oidc_auto_redirect: config.oidc_auto_redirect,
google_oauth: NamedOauthConfig {
enabled: config.google_oauth.enabled,
client_id: empty_or_redacted(&config.google_oauth.client_id),
@@ -1051,11 +954,6 @@ impl CoreConfig {
cors_allowed_origins: config.cors_allowed_origins,
cors_allow_credentials: config.cors_allow_credentials,
session_allow_cross_site: config.session_allow_cross_site,
x_content_type_options: config.x_content_type_options,
x_frame_options: config.x_frame_options,
x_xss_protection: config.x_xss_protection,
referrer_policy: config.referrer_policy,
content_security_policy: config.content_security_policy,
webhook_secret: empty_or_redacted(&config.webhook_secret),
webhook_base_url: config.webhook_base_url,
database: config.database.sanitized(),
@@ -1134,21 +1032,6 @@ impl mogh_server::ServerConfig for &CoreConfig {
fn ssl_cert_file(&self) -> &str {
&self.ssl_cert_file
}
fn x_content_type_options(&self) -> &str {
&self.x_content_type_options
}
fn x_frame_options(&self) -> &str {
&self.x_frame_options
}
fn x_xss_protection(&self) -> &str {
&self.x_xss_protection
}
fn referrer_policy(&self) -> &str {
&self.referrer_policy
}
fn content_security_policy(&self) -> &str {
&self.content_security_policy
}
}
impl mogh_server::cors::CorsConfig for &CoreConfig {
@@ -119,7 +119,6 @@ impl DatabaseConfig {
Deserialize,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct GitProvider {
/// The git provider domain. Default: `github.com`.
#[serde(default = "default_git_provider")]
@@ -153,7 +152,6 @@ fn default_git_https() -> bool {
Deserialize,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct DockerRegistry {
/// The docker provider domain. Default: `docker.io`.
#[serde(default = "default_docker_provider")]
@@ -184,7 +182,6 @@ fn default_docker_provider() -> String {
Deserialize,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct ProviderAccount {
/// The account username. Required.
#[serde(alias = "account")]
-18
View File
@@ -80,10 +80,6 @@ pub type _PartialDeploymentConfig = PartialDeploymentConfig;
#[derive(Serialize, Deserialize, Debug, Clone, Builder, Partial)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[partial_derive(Serialize, Deserialize, Debug, Clone, Default)]
#[cfg_attr(
feature = "schemars",
partial_derive(schemars::JsonSchema)
)]
#[diff_derive(Serialize, Deserialize, Debug, Clone, Default)]
#[partial(skip_serializing_none, from, diff)]
pub struct DeploymentConfig {
@@ -93,10 +89,6 @@ pub struct DeploymentConfig {
/// swarm_id overrides server_id and the Deployment will be in Swarm mode.
#[serde(default, alias = "swarm")]
#[partial_attr(serde(alias = "swarm"))]
#[cfg_attr(
feature = "schemars",
partial_attr(schemars(rename = "swarm"))
)]
#[builder(default)]
pub swarm_id: String,
@@ -106,10 +98,6 @@ pub struct DeploymentConfig {
/// swarm_id overrides server_id and the Deployment will be in Swarm mode.
#[serde(default, alias = "server")]
#[partial_attr(serde(alias = "server"))]
#[cfg_attr(
feature = "schemars",
partial_attr(schemars(rename = "server"))
)]
#[builder(default)]
pub server_id: String,
@@ -367,7 +355,6 @@ impl utoipa::ToSchema for PartialDeploymentConfig {}
utoipa::ToSchema
))
)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[serde(tag = "type", content = "params")]
pub enum DeploymentImage {
/// Deploy any external image.
@@ -381,7 +368,6 @@ pub enum DeploymentImage {
Build {
/// The id of the Build
#[serde(default, alias = "build")]
#[cfg_attr(feature = "schemars", schemars(rename = "build"))]
build_id: String,
/// Use a custom / older version of the image produced by the build.
/// if version is 0.0.0, this means `latest` image.
@@ -464,8 +450,6 @@ pub enum DeploymentState {
Created,
/// Server mode only. Container is in restart loop
Restarting,
/// Server mode only. Container is in the process of stopping
Stopping,
/// Server mode only. Container is being removed
Removing,
/// Server mode only. Container is paused
@@ -493,7 +477,6 @@ impl From<ContainerStateStatusEnum> for DeploymentState {
ContainerStateStatusEnum::Restarting => {
DeploymentState::Restarting
}
ContainerStateStatusEnum::Stopping => DeploymentState::Stopping,
ContainerStateStatusEnum::Removing => DeploymentState::Removing,
ContainerStateStatusEnum::Exited => DeploymentState::Exited,
ContainerStateStatusEnum::Dead => DeploymentState::Dead,
@@ -517,7 +500,6 @@ impl From<ContainerStateStatusEnum> for DeploymentState {
AsRefStr,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum RestartMode {
#[default]
#[serde(rename = "no")]
@@ -8,8 +8,8 @@ use typeshare::typeshare;
use crate::entities::{I64, Usize};
use super::{
ContainerConfig, GraphDriverData, Mount, PortBinding,
ResourcesUlimits,
ContainerConfig, GraphDriverData, Mount, MountTypeEnum,
PortBinding, ResourcesUlimits,
};
/// Container summary returned by container list apis.
@@ -294,7 +294,6 @@ pub enum ContainerStateStatusEnum {
Paused,
Restarting,
Exited,
Stopping,
Removing,
Dead,
#[default]
@@ -859,8 +858,8 @@ pub enum HostConfigCgroupnsModeEnum {
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
pub struct MountPoint {
/// The mount type: - `bind` a mount of a file or directory from the host into the container. - `volume` a docker volume with the given `Name`. - `tmpfs` a `tmpfs`. - `npipe` a named pipe from the host into the container. - `cluster` a Swarm cluster volume
#[serde(rename = "Type")]
pub typ: Option<String>,
#[serde(default, rename = "Type")]
pub typ: MountTypeEnum,
/// Name is the name reference to the underlying data defined by `Source` e.g., the volume name.
#[serde(rename = "Name")]
+4 -14
View File
@@ -267,7 +267,7 @@ pub struct Mount {
/// - `tmpfs` Create a tmpfs with the given options. The mount source cannot be specified for tmpfs. - `npipe` Mounts a named pipe from the host into the container. Must exist prior to creating the container.
/// - `cluster` a Swarm cluster volume
#[serde(default, rename = "Type")]
pub typ: MountType,
pub typ: MountTypeEnum,
/// Whether the mount should be read-only.
#[serde(rename = "ReadOnly")]
@@ -301,8 +301,10 @@ pub struct Mount {
Default,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
pub enum MountType {
pub enum MountTypeEnum {
#[default]
#[serde(rename = "")]
Empty,
#[serde(rename = "bind")]
Bind,
#[serde(rename = "volume")]
@@ -641,15 +643,3 @@ pub struct TlsInfo {
#[serde(rename = "CertIssuerPublicKey")]
pub cert_issuer_public_key: Option<String>,
}
/// A map of topological domains to topological segments. For in depth details, see documentation for the Topology object in the CSI specification.
#[typeshare]
#[derive(
Debug, Clone, Default, PartialEq, Serialize, Deserialize,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
pub struct Topology {
#[serde(rename = "Segments")]
#[serde(skip_serializing_if = "Option::is_none")]
pub segments: Option<HashMap<String, String>>,
}
@@ -129,7 +129,6 @@ pub struct NodeSpec {
ValueEnum,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum NodeSpecRoleEnum {
#[default]
#[serde(rename = "")]
@@ -156,7 +155,6 @@ pub enum NodeSpecRoleEnum {
ValueEnum,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum NodeSpecAvailabilityEnum {
#[default]
#[serde(rename = "")]
+11 -8
View File
@@ -3,9 +3,9 @@ use std::collections::HashMap;
use serde::{Deserialize, Serialize};
use typeshare::typeshare;
use crate::entities::{I64, docker::Topology};
use crate::entities::I64;
use super::ObjectVersion;
use super::{ObjectVersion, PortBinding};
#[typeshare]
#[derive(
@@ -145,8 +145,8 @@ pub struct ClusterVolumeInfo {
pub volume_id: Option<String>,
/// The topology this volume is actually accessible from.
#[serde(rename = "AccessibleTopology")]
pub accessible_topology: Option<Vec<Topology>>,
#[serde(default, rename = "AccessibleTopology")]
pub accessible_topology: Vec<Topology>,
}
#[typeshare]
@@ -319,14 +319,17 @@ pub struct ClusterVolumeSpecAccessModeSecrets {
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
pub struct ClusterVolumeSpecAccessModeAccessibilityRequirements {
/// A list of required topologies, at least one of which the volume must be accessible from.
#[serde(rename = "Requisite")]
pub requisite: Option<Vec<Topology>>,
#[serde(default, rename = "Requisite")]
pub requisite: Vec<Topology>,
/// A list of topologies that the volume should attempt to be provisioned in.
#[serde(rename = "Preferred")]
pub preferred: Option<Vec<Topology>>,
#[serde(default, rename = "Preferred")]
pub preferred: Vec<Topology>,
}
#[typeshare]
pub type Topology = HashMap<String, Vec<PortBinding>>;
/// The desired capacity that the volume should be created with. If empty, the plugin will decide the capacity.
#[typeshare]
#[derive(
-15
View File
@@ -103,7 +103,6 @@ pub type _Serror = Serror;
Debug, Clone, Default, PartialEq, Serialize, Deserialize, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct NoData {}
pub trait MergePartial: Sized {
@@ -211,14 +210,11 @@ pub struct __Serror {
Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct SystemCommand {
#[serde(default)]
pub path: String,
#[serde(default, deserialize_with = "file_contents_deserializer")]
pub command: String,
#[serde(default)]
pub shell_mode: bool,
}
impl SystemCommand {
@@ -242,7 +238,6 @@ impl SystemCommand {
#[typeshare]
#[derive(Serialize, Debug, Clone, Copy, Default, PartialEq)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct Version {
pub major: i32,
pub minor: i32,
@@ -493,7 +488,6 @@ impl ImageDigest {
#[typeshare]
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct MaintenanceWindow {
/// Name for the maintenance window (required)
pub name: String,
@@ -926,7 +920,6 @@ pub enum DayOfWeek {
Deserialize,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum MaintenanceScheduleType {
/// Daily at the specified time
#[default]
@@ -1371,7 +1364,6 @@ pub enum SearchCombinator {
EnumString,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[serde(rename_all = "UPPERCASE")]
#[strum(serialize_all = "UPPERCASE")]
pub enum TerminationSignal {
@@ -1429,11 +1421,6 @@ pub enum TerminationSignal {
utoipa::ToSchema,
))
)]
#[cfg_attr(
feature = "schemars",
strum_discriminants(derive(schemars::JsonSchema))
)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[serde(tag = "type", content = "id")]
pub enum ResourceTarget {
System(String),
@@ -1590,7 +1577,6 @@ impl ResourceTargetVariant {
Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum ScheduleFormat {
#[default]
English,
@@ -1602,7 +1588,6 @@ pub enum ScheduleFormat {
Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[serde(rename_all = "snake_case")]
pub enum FileFormat {
#[default]
@@ -118,7 +118,6 @@ impl UserTarget {
Default,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum PermissionLevel {
/// No permissions.
#[default]
@@ -157,7 +156,6 @@ impl Default for &PermissionLevel {
Ord,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum SpecificPermission {
/// On **Server**
/// - Access the terminal apis
@@ -195,7 +193,6 @@ impl SpecificPermission {
#[typeshare]
#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct PermissionLevelAndSpecifics {
pub level: PermissionLevel,
#[cfg_attr(feature = "utoipa", schema(value_type = Vec<SpecificPermission>))]
-10
View File
@@ -82,20 +82,12 @@ pub type _PartialProcedureConfig = PartialProcedureConfig;
#[derive(Debug, Clone, Serialize, Deserialize, Partial, Builder)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[partial_derive(Debug, Clone, Default, Serialize, Deserialize)]
#[cfg_attr(
feature = "schemars",
partial_derive(schemars::JsonSchema)
)]
#[diff_derive(Debug, Clone, Default, Serialize, Deserialize)]
#[partial(skip_serializing_none, from, diff)]
pub struct ProcedureConfig {
/// The stages to be run by the procedure.
#[serde(default, alias = "stage")]
#[partial_attr(serde(alias = "stage"))]
#[cfg_attr(
feature = "schemars",
partial_attr(schemars(rename = "stage"))
)]
#[builder(default)]
pub stages: Vec<ProcedureStage>,
@@ -215,7 +207,6 @@ impl utoipa::ToSchema for PartialProcedureConfig {}
#[typeshare]
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct ProcedureStage {
/// A name for the procedure
pub name: String,
@@ -231,7 +222,6 @@ pub struct ProcedureStage {
#[typeshare]
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct EnabledExecution {
/// The execution request to run.
pub execution: Execution,
-12
View File
@@ -113,30 +113,18 @@ pub type _PartialRepoConfig = PartialRepoConfig;
#[derive(Serialize, Deserialize, Debug, Clone, Builder, Partial)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[partial_derive(Serialize, Deserialize, Debug, Clone, Default)]
#[cfg_attr(
feature = "schemars",
partial_derive(schemars::JsonSchema)
)]
#[diff_derive(Serialize, Deserialize, Debug, Clone, Default)]
#[partial(skip_serializing_none, from, diff)]
pub struct RepoConfig {
/// The server to clone the repo on.
#[serde(default, alias = "server")]
#[partial_attr(serde(alias = "server"))]
#[cfg_attr(
feature = "schemars",
partial_attr(schemars(rename = "server"))
)]
#[builder(default)]
pub server_id: String,
/// Attach a builder to 'build' the repo.
#[serde(default, alias = "builder")]
#[partial_attr(serde(alias = "builder"))]
#[cfg_attr(
feature = "schemars",
partial_attr(schemars(rename = "builder"))
)]
#[builder(default)]
pub builder_id: String,
-4
View File
@@ -96,10 +96,6 @@ pub type _PartialServerConfig = PartialServerConfig;
#[derive(Serialize, Deserialize, Debug, Clone, Builder, Partial)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[partial_derive(Serialize, Deserialize, Debug, Clone, Default)]
#[cfg_attr(
feature = "schemars",
partial_derive(schemars::JsonSchema)
)]
#[diff_derive(Serialize, Deserialize, Debug, Clone, Default)]
#[partial(skip_serializing_none, from, diff)]
pub struct ServerConfig {
-27
View File
@@ -293,10 +293,6 @@ pub type _PartialStackConfig = PartialStackConfig;
#[derive(Debug, Clone, Serialize, Deserialize, Builder, Partial)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[partial_derive(Debug, Clone, Default, Serialize, Deserialize)]
#[cfg_attr(
feature = "schemars",
partial_derive(schemars::JsonSchema)
)]
#[diff_derive(Debug, Clone, Default, Serialize, Deserialize)]
#[partial(skip_serializing_none, from, diff)]
pub struct StackConfig {
@@ -306,10 +302,6 @@ pub struct StackConfig {
/// swarm_id overrides server_id and the Stack will be in Swarm mode.
#[serde(default, alias = "swarm")]
#[partial_attr(serde(alias = "swarm"))]
#[cfg_attr(
feature = "schemars",
partial_attr(schemars(rename = "swarm"))
)]
#[builder(default)]
pub swarm_id: String,
@@ -319,10 +311,6 @@ pub struct StackConfig {
/// swarm_id overrides server_id and the Stack will be in Swarm mode.
#[serde(default, alias = "server")]
#[partial_attr(serde(alias = "server"))]
#[cfg_attr(
feature = "schemars",
partial_attr(schemars(rename = "server"))
)]
#[builder(default)]
pub server_id: String,
@@ -383,17 +371,6 @@ pub struct StackConfig {
#[builder(default)]
pub auto_update_all_services: bool,
/// Ignore certain services during Global Auto Update polling.
/// Services listed here are skipped only in the global auto-update flow.
/// Manual checks still include all services.
#[serde(default, deserialize_with = "string_list_deserializer")]
#[partial_attr(serde(
default,
deserialize_with = "option_string_list_deserializer"
))]
#[builder(default)]
pub auto_update_skip_services: Vec<String>,
/// Whether to run `docker compose down` before `compose up`.
#[serde(default)]
#[builder(default)]
@@ -711,7 +688,6 @@ impl Default for StackConfig {
poll_for_updates: Default::default(),
auto_update: Default::default(),
auto_update_all_services: Default::default(),
auto_update_skip_services: Default::default(),
ignore_services: Default::default(),
pre_deploy: Default::default(),
post_deploy: Default::default(),
@@ -939,7 +915,6 @@ pub struct StackRemoteFileContents {
Deserialize,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum StackFileRequires {
/// Diff requires service redeploy.
#[serde(alias = "redeploy")]
@@ -958,7 +933,6 @@ pub enum StackFileRequires {
#[typeshare]
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct AdditionalEnvFile {
/// File path relative to run directory
pub path: String,
@@ -1038,7 +1012,6 @@ impl<'de> Deserialize<'de> for AdditionalEnvFile {
#[typeshare]
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct StackFileDependency {
/// Specify the file
pub path: String,
-8
View File
@@ -82,10 +82,6 @@ pub type _PartialSwarmConfig = PartialSwarmConfig;
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[partial_derive(Serialize, Deserialize, Debug, Clone, Default)]
#[cfg_attr(
feature = "schemars",
partial_derive(schemars::JsonSchema)
)]
#[diff_derive(Serialize, Deserialize, Debug, Clone, Default)]
#[partial(skip_serializing_none, from, diff)]
pub struct SwarmConfig {
@@ -94,10 +90,6 @@ pub struct SwarmConfig {
/// tries the next Server.
#[serde(default, alias = "servers")]
#[partial_attr(serde(alias = "servers"))]
#[cfg_attr(
feature = "schemars",
partial_attr(schemars(rename = "servers"))
)]
#[builder(default)]
pub server_ids: Vec<String>,
-4
View File
@@ -186,10 +186,6 @@ pub type _PartialResourceSyncConfig = PartialResourceSyncConfig;
#[derive(Debug, Clone, Serialize, Deserialize, Builder, Partial)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[partial_derive(Debug, Clone, Default, Serialize, Deserialize)]
#[cfg_attr(
feature = "schemars",
partial_derive(schemars::JsonSchema)
)]
#[diff_derive(Debug, Clone, Default, Serialize, Deserialize)]
#[partial(skip_serializing_none, from, diff)]
pub struct ResourceSyncConfig {
+7 -41
View File
@@ -26,134 +26,102 @@ use super::{
#[typeshare]
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[cfg_attr(feature = "schemars", schemars(rename = "Resources"))]
pub struct ResourcesToml {
/// Declare a swarm
#[serde(
default,
alias = "swarm",
skip_serializing_if = "Vec::is_empty"
)]
#[cfg_attr(feature = "schemars", schemars(rename = "swarm"))]
pub swarms: Vec<ResourceToml<_PartialSwarmConfig>>,
/// Declare a server
#[serde(
default,
alias = "server",
skip_serializing_if = "Vec::is_empty"
)]
#[cfg_attr(feature = "schemars", schemars(rename = "server"))]
pub servers: Vec<ResourceToml<_PartialServerConfig>>,
/// Declare a stack
#[serde(
default,
alias = "stack",
skip_serializing_if = "Vec::is_empty"
)]
#[cfg_attr(feature = "schemars", schemars(rename = "stack"))]
pub stacks: Vec<ResourceToml<_PartialStackConfig>>,
/// Declare a deployment
#[serde(
default,
alias = "deployment",
skip_serializing_if = "Vec::is_empty"
)]
#[cfg_attr(feature = "schemars", schemars(rename = "deployment"))]
pub deployments: Vec<ResourceToml<_PartialDeploymentConfig>>,
/// Declare a build
#[serde(
default,
alias = "stack",
skip_serializing_if = "Vec::is_empty"
)]
pub stacks: Vec<ResourceToml<_PartialStackConfig>>,
#[serde(
default,
alias = "build",
skip_serializing_if = "Vec::is_empty"
)]
#[cfg_attr(feature = "schemars", schemars(rename = "build"))]
pub builds: Vec<ResourceToml<_PartialBuildConfig>>,
/// Declare a repo
#[serde(
default,
alias = "repo",
skip_serializing_if = "Vec::is_empty"
)]
#[cfg_attr(feature = "schemars", schemars(rename = "repo"))]
pub repos: Vec<ResourceToml<_PartialRepoConfig>>,
/// Declare a procedure
#[serde(
default,
alias = "procedure",
skip_serializing_if = "Vec::is_empty"
)]
#[cfg_attr(feature = "schemars", schemars(rename = "procedure"))]
pub procedures: Vec<ResourceToml<_PartialProcedureConfig>>,
/// Declare an action
#[serde(
default,
alias = "action",
skip_serializing_if = "Vec::is_empty"
)]
#[cfg_attr(feature = "schemars", schemars(rename = "action"))]
pub actions: Vec<ResourceToml<_PartialActionConfig>>,
/// Declare an alerter
#[serde(
default,
alias = "alerter",
skip_serializing_if = "Vec::is_empty"
)]
#[cfg_attr(feature = "schemars", schemars(rename = "alerter"))]
pub alerters: Vec<ResourceToml<_PartialAlerterConfig>>,
/// Declare a builder
#[serde(
default,
alias = "builder",
skip_serializing_if = "Vec::is_empty"
)]
#[cfg_attr(feature = "schemars", schemars(rename = "builder"))]
pub builders: Vec<ResourceToml<_PartialBuilderConfig>>,
/// Declare a resource sync
#[serde(
default,
alias = "resource_sync",
skip_serializing_if = "Vec::is_empty"
)]
#[cfg_attr(
feature = "schemars",
schemars(rename = "resource_sync")
)]
pub resource_syncs: Vec<ResourceToml<_PartialResourceSyncConfig>>,
/// Declare a user group
#[serde(
default,
alias = "user_group",
skip_serializing_if = "Vec::is_empty"
)]
#[cfg_attr(feature = "schemars", schemars(rename = "user_group"))]
pub user_groups: Vec<UserGroupToml>,
/// Declare a variable
#[serde(
default,
alias = "variable",
skip_serializing_if = "Vec::is_empty"
)]
#[cfg_attr(feature = "schemars", schemars(rename = "variable"))]
pub variables: Vec<Variable>,
}
#[typeshare]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct ResourceToml<PartialConfig: Default> {
/// The resource name. Required
pub name: String,
@@ -197,7 +165,6 @@ fn is_false(b: &bool) -> bool {
#[typeshare]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct UserGroupToml {
/// User group name
pub name: String,
@@ -224,7 +191,6 @@ pub struct UserGroupToml {
#[typeshare]
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct PermissionToml {
/// Id can be:
/// - resource name. `id = "abcd-build"`
-1
View File
@@ -6,7 +6,6 @@ use typeshare::typeshare;
#[typeshare]
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[cfg_attr(
feature = "mongo",
derive(mongo_indexed::derive::MongoIndexed)
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "komodo_client",
"version": "2.2.0",
"version": "2.1.1",
"description": "Komodo client package",
"homepage": "https://komo.do",
"main": "dist/lib.js",
@@ -13,7 +13,7 @@
"build": "tsc"
},
"dependencies": {
"mogh_auth_client": "^1.5.0"
"mogh_auth_client": "^1.2.1"
},
"devDependencies": {
"typescript": "^6.0.2"
+8 -34
View File
@@ -612,7 +612,6 @@ export interface ImageRegistryConfig {
export interface SystemCommand {
path?: string;
command?: string;
shell_mode?: boolean;
}
/** The build configuration. */
@@ -1428,8 +1427,6 @@ export enum DeploymentState {
Created = "created",
/** Server mode only. Container is in restart loop */
Restarting = "restarting",
/** Server mode only. Container is in the process of stopping */
Stopping = "stopping",
/** Server mode only. Container is being removed */
Removing = "removing",
/** Server mode only. Container is paused */
@@ -2473,12 +2470,6 @@ export interface StackConfig {
* Komodo will redeploy the whole Stack (all services).
*/
auto_update_all_services?: boolean;
/**
* Ignore certain services during Global Auto Update polling.
* Services listed here are skipped only in the global auto-update flow.
* Manual checks still include all services.
*/
auto_update_skip_services?: string[];
/** Whether to run `docker compose down` before `compose up`. */
destroy_before_deploy?: boolean;
/** Whether to skip secret interpolation into the stack environment variables. */
@@ -2965,7 +2956,6 @@ export enum ContainerStateStatusEnum {
Paused = "paused",
Restarting = "restarting",
Exited = "exited",
Stopping = "stopping",
Removing = "removing",
Dead = "dead",
Empty = "",
@@ -3097,7 +3087,8 @@ export interface RestartPolicy {
MaximumRetryCount?: I64;
}
export enum MountType {
export enum MountTypeEnum {
Empty = "",
Bind = "bind",
Volume = "volume",
Image = "image",
@@ -3169,7 +3160,7 @@ export interface Mount {
* - `tmpfs` Create a tmpfs with the given options. The mount source cannot be specified for tmpfs. - `npipe` Mounts a named pipe from the host into the container. Must exist prior to creating the container.
* - `cluster` a Swarm cluster volume
*/
Type?: MountType;
Type?: MountTypeEnum;
/** Whether the mount should be read-only. */
ReadOnly?: boolean;
/** The consistency requirement for the mount: `default`, `consistent`, `cached`, or `delegated`. */
@@ -3342,7 +3333,7 @@ export interface GraphDriverData {
/** MountPoint represents a mount point configuration inside the container. This is used for reporting the mountpoints in use by a container. */
export interface MountPoint {
/** The mount type: - `bind` a mount of a file or directory from the host into the container. - `volume` a docker volume with the given `Name`. - `tmpfs` a `tmpfs`. - `npipe` a named pipe from the host into the container. - `cluster` a Swarm cluster volume */
Type?: string;
Type?: MountTypeEnum;
/** Name is the name reference to the underlying data defined by `Source` e.g., the volume name. */
Name?: string;
/** Source location of the mount. For volumes, this contains the storage location of the volume (within `/var/lib/docker/volumes/`). For bind-mounts, and `npipe`, this contains the source (host) part of the bind-mount. For `tmpfs` mount points, this field is empty. */
@@ -4302,10 +4293,7 @@ export interface ClusterVolumeSpecAccessModeSecrets {
Secret?: string;
}
/** A map of topological domains to topological segments. For in depth details, see documentation for the Topology object in the CSI specification. */
export interface Topology {
Segments?: Record<string, string>;
}
export type Topology = Record<string, PortBinding[]>;
/** Requirements for the accessible topology of the volume. These fields are optional. For an in-depth description of what these fields mean, see the CSI specification. */
export interface ClusterVolumeSpecAccessModeAccessibilityRequirements {
@@ -6828,8 +6816,7 @@ export interface CreateOnboardingKey {
expires?: I64;
/**
* Optionally specify an existing private key, otherwise
* generate fresh key. This key is not stored directly,
* only the public key.
* generate fresh key.
*/
private_key?: string;
/** Default tags to apply to Servers created using this key. */
@@ -7451,31 +7438,18 @@ export interface UserGroupToml {
/** Specifies resources to sync on Komodo */
export interface ResourcesToml {
/** Declare a swarm */
swarms?: ResourceToml<_PartialSwarmConfig>[];
/** Declare a server */
servers?: ResourceToml<_PartialServerConfig>[];
/** Declare a stack */
stacks?: ResourceToml<_PartialStackConfig>[];
/** Declare a deployment */
deployments?: ResourceToml<_PartialDeploymentConfig>[];
/** Declare a build */
stacks?: ResourceToml<_PartialStackConfig>[];
builds?: ResourceToml<_PartialBuildConfig>[];
/** Declare a repo */
repos?: ResourceToml<_PartialRepoConfig>[];
/** Declare a procedure */
procedures?: ResourceToml<_PartialProcedureConfig>[];
/** Declare an action */
actions?: ResourceToml<_PartialActionConfig>[];
/** Declare an alerter */
alerters?: ResourceToml<_PartialAlerterConfig>[];
/** Declare a builder */
builders?: ResourceToml<_PartialBuilderConfig>[];
/** Declare a resource sync */
resource_syncs?: ResourceToml<_PartialResourceSyncConfig>[];
/** Declare a user group */
user_groups?: UserGroupToml[];
/** Declare a variable */
variables?: Variable[];
}
@@ -7764,7 +7738,7 @@ export interface GetCoreInfoResponse {
enable_fancy_toml: boolean;
/** TZ identifier Core is using, if manually set. */
timezone: string;
/** Public key for Core / Periphery authentication. */
/** Default public key allowing this Core to authenticate to Periphery agents. */
public_key: string;
}
+4 -4
View File
@@ -7,10 +7,10 @@ jwt-decode@^4.0.0:
resolved "https://registry.yarnpkg.com/jwt-decode/-/jwt-decode-4.0.0.tgz#2270352425fd413785b2faf11f6e755c5151bd4b"
integrity sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==
mogh_auth_client@^1.5.0:
version "1.5.0"
resolved "https://registry.yarnpkg.com/mogh_auth_client/-/mogh_auth_client-1.5.0.tgz#f54b8ae35648d5bf1e60d7b67fcdcef45b0ccd7a"
integrity sha512-eUQmx682AzJRaY4QJSALtIGxXzg2r2Tr8exnDeFMrNe0Ibn4Oqm3h9SkOzYiqqZjKQ13wvHm0RoxT2QKo+908g==
mogh_auth_client@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/mogh_auth_client/-/mogh_auth_client-1.2.1.tgz#c8b5e9da101dc8da7b30586e5c5463f5f7a95edb"
integrity sha512-8uUjgqagwbMW8BKtTRzfQ4txpw+54hqLszbIvcYf99murVIQu5+NsRZ8/vjP/fOMawgXJXCVsR6O2lamm1BCnQ==
dependencies:
jwt-decode "^4.0.0"
+1 -2
View File
@@ -145,7 +145,6 @@ PERIPHERY_CORE_PUBLIC_KEYS=file:/config/keys/core.pub
## ------ ./my_stack_2
## --- ./repos
## ------ ./my_repo_1
## --- ./builds
PERIPHERY_ROOT_DIRECTORY=/etc/komodo
## Specify whether to disable the terminals feature
@@ -165,4 +164,4 @@ PERIPHERY_INCLUDE_DISK_MOUNTS=/etc/hostname
## Prettier logging with empty lines between logs
PERIPHERY_LOGGING_PRETTY=false
## More human readable logging of startup config (multi-line)
PERIPHERY_PRETTY_STARTUP_CONFIG=false
PERIPHERY_PRETTY_STARTUP_CONFIG=false
+3 -60
View File
@@ -167,20 +167,6 @@ init_admin_password = "changeme"
## Default: false
disable_user_registration = false
## Disable local (username/password) user registration only.
## When set to true, the "Sign Up" button is hidden and local signups are blocked,
## but OIDC and other external provider signups may still be allowed.
## If not set, falls back to `disable_user_registration`.
## Env: KOMODO_DISABLE_LOCAL_USER_REGISTRATION
# disable_local_user_registration = true
## Disable OIDC user registration only.
## When set to true, new users cannot register via OIDC,
## but local and other provider signups may still be allowed.
## If not set, falls back to `disable_user_registration`.
## Env: KOMODO_DISABLE_OIDC_USER_REGISTRATION
# disable_oidc_user_registration = true
## New users will be automatically enabled when they sign up.
## Otherwise, new users will be disabled on first login.
## The first user to login will always be enabled on creation.
@@ -281,13 +267,6 @@ oidc_use_full_email = false
## Default: empty
oidc_additional_audiences = []
## Automatically redirect unauthenticated users to the OIDC provider
## instead of showing the login page.
## Users can bypass the redirect by appending `?disableAutoLogin` to the login URL.
## Env: KOMODO_OIDC_AUTO_REDIRECT
## Default: false
oidc_auto_redirect = false
#########
# OAUTH #
#########
@@ -345,9 +324,9 @@ auth_rate_limit_max_attempts = 5
## Default: 15
auth_rate_limit_window_seconds = 15
############################
# CORS / SESSION / HEADERS #
############################
##################
# CORS / SESSION #
##################
## Specifically set list of CORS allowed origins.
## If empty, allows all origins (`*`).
@@ -364,44 +343,8 @@ cors_allow_credentials = false
## Enabling this sets 'SameSite=None', which allows externally
## hosted UIs to use the login flows.
## Env: KOMODO_SESSION_ALLOW_CROSS_SITE
## Default: false
session_allow_cross_site = false
## `X-Content-Type-Options` header value.
## Set as empty string to omit the header.
## Env: KOMODO_X_CONTENT_TYPE_OPTIONS
## Default: "nosniff"
x_content_type_options = "nosniff"
## `X-Frame-Options` header value.
## Set as empty string to omit the header.
## Use "SAMEORIGIN" to allow same-origin embedding only.
## Env: KOMODO_X_FRAME_OPTIONS
## Default: "DENY"
x_frame_options = "DENY"
## `X-Xss-Protection` header value.
## Set as empty string to omit the header.
## Env: KOMODO_X_XSS_PROTECTION
## Default: "1; mode=block"
x_xss_protection = "1; mode=block"
## Apply Referrer Policy directives.
## If empty string, no header is applied.
## Env: KOMODO_REFERRER_POLICY
## Default: "strict-origin-when-cross-origin"
referrer_policy = "strict-origin-when-cross-origin"
## Apply Content Security Policy directives.
## If empty string, no header is applied.
## Env: KOMODO_CONTENT_SECURITY_POLICY
## Default: ""
##
## Example:
## `default-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'; form-action 'self'`
content_security_policy = ""
##################
# POLL INTERVALS #
##################
+1 -2
View File
@@ -33,7 +33,6 @@
## ------ ./my_stack_2
## --- ./repos
## ------ ./my_repo_1
## --- ./builds
## Each specific sub-directory (like ./stacks) can be overridden below.
## Env: PERIPHERY_ROOT_DIRECTORY
## Default: /etc/komodo
@@ -292,4 +291,4 @@ pretty_startup_config = false
## Provide periphery-based secrets
# [secrets]
# SECRET_1 = "value_1"
# SECRET_2 = "value_2"
# SECRET_2 = "value_2"
+2 -2
View File
@@ -141,7 +141,7 @@ Core and Periphery authenticate using automatically generated public/private key
### How it works
1. When you create an **onboarding key** in the UI or API, Komodo Core generates a key pair, and the private key is returned once to the user as the "onboarding key".
1. When you create an **onboarding key** in the UI or API, Komodo Core generates a key pair, and the private key is returned once the the user as the "onboarding key".
2. When Periphery first connects using the onboarding key, it generates its own key pair, and sends just the public key to Core.
Core stores this public key for each Server.
3. All subsequent communication is authenticated by performing a
@@ -163,7 +163,7 @@ Keys can also be specified inline in config instead of as file paths.
### Automatic key rotation
Komodo supports automatic rotation of the Periphery key pairs.
When triggered, already connected Periphery agents generate a new key pair and send the public key to Komodo Core,
When triggered, already connected Periphery agents generate a new key pair and sends the new public key to Komodo Core,
which updates its expected public key for that server.
Each Server has an `auto_rotate_keys` setting (default: `true`) that controls whether it participates in the bulk `RotateAllServerKeys` operation.
+1 -1
View File
@@ -1,4 +1,4 @@
FROM rust:1.95.0-trixie as builder
FROM rust:1.94.1-bullseye as builder
WORKDIR /builder
COPY . .
+1 -1
View File
@@ -1,4 +1,4 @@
FROM rust:1.95.0-trixie as builder
FROM rust:1.94.1-bullseye as builder
WORKDIR /builder
COPY . .
+836
View File
@@ -0,0 +1,836 @@
import { KOMODO_BASE_URL } from "@main";
import { KomodoClient, Types } from "komodo_client";
import {
AuthResponses,
ExecuteResponses,
ReadResponses,
UserResponses,
WriteResponses,
} from "komodo_client/dist/responses";
import {
UseMutationOptions,
UseQueryOptions,
useMutation,
useQuery,
useQueryClient,
} from "@tanstack/react-query";
import { UsableResource } from "@types";
import { useToast } from "@ui/use-toast";
import { atom, useAtom } from "jotai";
import { atomFamily } from "jotai/utils";
import { useEffect, useMemo, useState } from "react";
import { useParams } from "react-router-dom";
import { has_minimum_permissions, RESOURCE_TARGETS } from "./utils";
export const atomWithStorage = <T>(key: string, init: T) => {
const stored = localStorage.getItem(key);
const inner = atom(stored ? JSON.parse(stored) : init);
return atom(
(get) => get(inner),
(_, set, newValue) => {
set(inner, newValue);
localStorage.setItem(key, JSON.stringify(newValue));
}
);
};
type LoginTokens = {
/** Current User ID */
current: string | undefined;
/** Array of logged in user ids / tokens */
tokens: Array<Types.JwtResponse>;
};
const LOGIN_TOKENS_KEY = "komodo-auth-tokens-v1";
export const LOGIN_TOKENS = (() => {
const stored = localStorage.getItem(LOGIN_TOKENS_KEY);
let tokens: LoginTokens = stored
? JSON.parse(stored)
: { current: undefined, tokens: [] };
const update_local_storage = () => {
localStorage.setItem(LOGIN_TOKENS_KEY, JSON.stringify(tokens));
};
const accounts = () => {
const current = tokens.tokens.find((t) => t.user_id === tokens.current);
const filtered = tokens.tokens.filter((t) => t.user_id !== tokens.current);
return current ? [current, ...filtered] : filtered;
};
const add_and_change = (user_id: string, jwt: string) => {
const filtered = tokens.tokens.filter((t) => t.user_id !== user_id);
filtered.push({ user_id, jwt });
filtered.sort();
tokens = {
current: user_id,
tokens: filtered,
};
update_local_storage();
};
const remove = (user_id: string) => {
const filtered = tokens.tokens.filter((t) => t.user_id !== user_id);
tokens = {
current:
tokens.current === user_id ? filtered[0]?.user_id : tokens.current,
tokens: filtered,
};
update_local_storage();
};
const remove_all = () => {
tokens = {
current: undefined,
tokens: [],
};
update_local_storage();
};
const change = (to_id: string) => {
tokens = {
current: to_id,
tokens: tokens.tokens,
};
update_local_storage();
};
return {
jwt: () =>
tokens.current
? (tokens.tokens.find((t) => t.user_id === tokens.current)?.jwt ?? "")
: "",
accounts,
add_and_change,
remove,
remove_all,
change,
};
})();
export const komodo_client = () =>
KomodoClient(KOMODO_BASE_URL, {
type: "jwt",
params: { jwt: LOGIN_TOKENS.jwt() },
});
// ============== RESOLVER ==============
export const useLoginOptions = () => {
return useQuery({
queryKey: ["GetLoginOptions"],
queryFn: () => komodo_client().auth("GetLoginOptions", {}),
refetchInterval: 30_000,
});
};
export const useUser = () => {
const userReset = useUserReset();
const hasJwt = !!LOGIN_TOKENS.jwt();
const query = useQuery({
queryKey: ["GetUser"],
queryFn: () => komodo_client().auth("GetUser", {}),
refetchInterval: 30_000,
enabled: hasJwt,
});
useEffect(() => {
if (query.data && query.error) {
userReset();
}
}, [query.data, query.error]);
return query;
};
export const useUserInvalidate = () => {
const qc = useQueryClient();
return () => {
qc.invalidateQueries({ queryKey: ["GetUser"] });
};
};
export const useUserReset = () => {
const qc = useQueryClient();
return () => {
qc.resetQueries({ queryKey: ["GetUser"] });
};
};
export const useRead = <
T extends Types.ReadRequest["type"],
R extends Extract<Types.ReadRequest, { type: T }>,
P extends R["params"],
C extends Omit<
UseQueryOptions<
ReadResponses[R["type"]],
unknown,
ReadResponses[R["type"]],
(T | P)[]
>,
"queryFn" | "queryKey"
>,
>(
type: T,
params: P,
config?: C
) => {
const hasJwt = !!LOGIN_TOKENS.jwt();
return useQuery({
queryKey: [type, params],
queryFn: () => komodo_client().read<T, R>(type, params),
enabled: hasJwt && (config?.enabled !== false),
...config,
});
};
export const useInvalidate = () => {
const qc = useQueryClient();
return <
Type extends Types.ReadRequest["type"],
Params extends Extract<Types.ReadRequest, { type: Type }>["params"],
>(
...keys: Array<[Type] | [Type, Params]>
) => keys.forEach((key) => qc.invalidateQueries({ queryKey: key }));
};
export const useManageUser = <
T extends Types.UserRequest["type"],
R extends Extract<Types.UserRequest, { type: T }>,
P extends R["params"],
C extends Omit<
UseMutationOptions<UserResponses[T], unknown, P, unknown>,
"mutationKey" | "mutationFn"
>,
>(
type: T,
config?: C
) => {
const { toast } = useToast();
return useMutation({
mutationKey: [type],
mutationFn: (params: P) => komodo_client().user<T, R>(type, params),
onError: (e: { result: { error?: string; trace?: string[] } }, v, c) => {
console.log("Auth error:", e);
const msg = e.result?.error ?? "Unknown error. See console.";
const detail = e.result?.trace
?.map((msg) => msg[0].toUpperCase() + msg.slice(1))
.join(" | ");
let msg_log = msg ? msg[0].toUpperCase() + msg.slice(1) + " | " : "";
if (detail) {
msg_log += detail + " | ";
}
toast({
title: `Request ${type} Failed`,
description: `${msg_log}See console for details`,
variant: "destructive",
});
config?.onError && config.onError(e, v, c);
},
...config,
});
};
export const useWrite = <
T extends Types.WriteRequest["type"],
R extends Extract<Types.WriteRequest, { type: T }>,
P extends R["params"],
C extends Omit<
UseMutationOptions<WriteResponses[R["type"]], unknown, P, unknown>,
"mutationKey" | "mutationFn"
>,
>(
type: T,
config?: C
) => {
const { toast } = useToast();
return useMutation({
mutationKey: [type],
mutationFn: (params: P) => komodo_client().write<T, R>(type, params),
onError: (e: { result: { error?: string; trace?: string[] } }, v, c) => {
console.log("Write error:", e);
const msg = e.result.error ?? "Unknown error. See console.";
const detail = e.result?.trace
?.map((msg) => msg[0].toUpperCase() + msg.slice(1))
.join(" | ");
let msg_log = msg ? msg[0].toUpperCase() + msg.slice(1) + " | " : "";
if (detail) {
msg_log += detail + " | ";
}
toast({
title: `Write request ${type} failed`,
description: `${msg_log}See console for details`,
variant: "destructive",
});
config?.onError && config.onError(e, v, c);
},
...config,
});
};
export const useExecute = <
T extends Types.ExecuteRequest["type"],
R extends Extract<Types.ExecuteRequest, { type: T }>,
P extends R["params"],
C extends Omit<
UseMutationOptions<ExecuteResponses[T], unknown, P, unknown>,
"mutationKey" | "mutationFn"
>,
>(
type: T,
config?: C
) => {
const { toast } = useToast();
return useMutation({
mutationKey: [type],
mutationFn: (params: P) => komodo_client().execute<T, R>(type, params),
onError: (e: { result: { error?: string; trace?: string[] } }, v, c) => {
console.log("Execute error:", e);
const msg = e.result.error ?? "Unknown error. See console.";
const detail = e.result?.trace
?.map((msg) => msg[0].toUpperCase() + msg.slice(1))
.join(" | ");
let msg_log = msg ? msg[0].toUpperCase() + msg.slice(1) + " | " : "";
if (detail) {
msg_log += detail + " | ";
}
toast({
title: `Execute request ${type} failed`,
description: `${msg_log}See console for details`,
variant: "destructive",
});
config?.onError && config.onError(e, v, c);
},
...config,
});
};
export const useAuth = <
T extends Types.AuthRequest["type"],
R extends Extract<Types.AuthRequest, { type: T }>,
P extends R["params"],
C extends Omit<
UseMutationOptions<AuthResponses[T], unknown, P, unknown>,
"mutationKey" | "mutationFn"
>,
>(
type: T,
config?: C
) => {
const { toast } = useToast();
return useMutation({
mutationKey: [type],
mutationFn: (params: P) => komodo_client().auth<T, R>(type, params),
onError: (e: { result: { error?: string; trace?: string[] } }, v, c) => {
console.log("Auth error:", e);
const msg = e.result.error ?? "Unknown error. See console.";
const detail = e.result?.trace
?.map((msg) => msg[0].toUpperCase() + msg.slice(1))
.join(" | ");
let msg_log = msg ? msg[0].toUpperCase() + msg.slice(1) + " | " : "";
if (detail) {
msg_log += detail + " | ";
}
toast({
title: `Auth request ${type} failed`,
description: `${msg_log}See console for details`,
variant: "destructive",
});
config?.onError && config.onError(e, v, c);
},
...config,
});
};
// ============== UTILITY ==============
export const useResourceParamType = () => {
const type = useParams().type;
if (!type) return undefined;
if (type === "resource-syncs") return "ResourceSync";
return (type[0].toUpperCase() + type.slice(1, -1)) as UsableResource;
};
type ResourceMap = {
[Resource in UsableResource]: Types.ResourceListItem<unknown>[] | undefined;
};
export const useAllResources = (): ResourceMap => {
return {
Server: useRead("ListServers", {}).data,
Stack: useRead("ListStacks", {}).data,
Deployment: useRead("ListDeployments", {}).data,
Build: useRead("ListBuilds", {}).data,
Repo: useRead("ListRepos", {}).data,
Procedure: useRead("ListProcedures", {}).data,
Action: useRead("ListActions", {}).data,
Builder: useRead("ListBuilders", {}).data,
Alerter: useRead("ListAlerters", {}).data,
ResourceSync: useRead("ListResourceSyncs", {}).data,
};
};
// Returns true if Komodo has no resources.
export const useNoResources = () => {
const resources = useAllResources();
for (const target of RESOURCE_TARGETS) {
if (resources[target] && resources[target].length) {
return false;
}
}
return true;
};
/** returns function that takes a resource target and checks if it exists */
export const useCheckResourceExists = () => {
const resources = useAllResources();
return (target: Types.ResourceTarget) => {
return (
resources[target.type as UsableResource]?.some(
(resource) => resource.id === target.id
) || false
);
};
};
export const useFilterResources = <Info>(
resources?: Types.ResourceListItem<Info>[],
search?: string
) => {
const tags = useTagsFilter();
const searchSplit = search?.toLowerCase()?.split(" ") || [];
return (
resources?.filter(
(resource) =>
tags.every((tag: string) => resource.tags.includes(tag)) &&
(searchSplit.length > 0
? searchSplit.every((search) =>
resource.name.toLowerCase().includes(search)
)
: true)
) ?? []
);
};
export const usePushRecentlyViewed = ({ type, id }: Types.ResourceTarget) => {
const userInvalidate = useUserInvalidate();
const push = useManageUser("PushRecentlyViewed", {
onSuccess: userInvalidate,
}).mutate;
const exists = useRead(`List${type as UsableResource}s`, {}).data?.find(
(r) => r.id === id
)
? true
: false;
useEffect(() => {
exists && push({ resource: { type, id } });
}, [exists, push]);
return () => push({ resource: { type, id } });
};
export const useSetTitle = (more?: string) => {
const info = useRead("GetCoreInfo", {}).data;
const title = more ? `${more} | ${info?.title}` : info?.title;
useEffect(() => {
if (title) {
document.title = title;
}
}, [title]);
};
const tagsAtom = atomWithStorage<string[]>("tags-v0", []);
export const useTags = () => {
const [tags, setTags] = useAtom<string[]>(tagsAtom);
const add_tag = (tag_id: string) => setTags([...tags, tag_id]);
const remove_tag = (tag_id: string) =>
setTags(tags.filter((id) => id !== tag_id));
const toggle_tag = (tag_id: string) => {
if (tags.includes(tag_id)) {
remove_tag(tag_id);
} else {
add_tag(tag_id);
}
};
const clear_tags = () => setTags([]);
return {
tags,
add_tag,
remove_tag,
toggle_tag,
clear_tags,
};
};
export const useTagsFilter = () => {
const [tags] = useAtom<string[]>(tagsAtom);
return tags;
};
export type LocalStorageSetter<T> = (state: T) => T;
export const useLocalStorage = <T>(
key: string,
init: T
): [T, (state: T | LocalStorageSetter<T>) => void] => {
const stored = localStorage.getItem(key);
const parsed = stored ? (JSON.parse(stored) as T) : undefined;
const [state, inner_set] = useState<T>(parsed ?? init);
const set = (state: T | LocalStorageSetter<T>) => {
inner_set((prev_state) => {
const new_val =
typeof state === "function"
? (state as LocalStorageSetter<T>)(prev_state)
: state;
localStorage.setItem(key, JSON.stringify(new_val));
return new_val;
});
};
return [state, set];
};
export const useKeyListener = (listenKey: string, onPress: () => void) => {
useEffect(() => {
const keydown = (e: KeyboardEvent) => {
// This will ignore Shift + listenKey if it is sent from input / textarea
const target = e.target as any;
if (target.matches("input") || target.matches("textarea")) return;
if (e.key === listenKey) {
e.preventDefault();
onPress();
}
};
document.addEventListener("keydown", keydown);
return () => document.removeEventListener("keydown", keydown);
});
};
export const useShiftKeyListener = (listenKey: string, onPress: () => void) => {
useEffect(() => {
const keydown = (e: KeyboardEvent) => {
// This will ignore Shift + listenKey if it is sent from input / textarea
const target = e.target as any;
if (target.matches("input") || target.matches("textarea")) return;
if (e.shiftKey && e.key === listenKey) {
e.preventDefault();
onPress();
}
};
document.addEventListener("keydown", keydown);
return () => document.removeEventListener("keydown", keydown);
});
};
/** Listens for ctrl (or CMD on mac) + the listenKey */
export const useCtrlKeyListener = (listenKey: string, onPress: () => void) => {
useEffect(() => {
const keydown = (e: KeyboardEvent) => {
if ((e.ctrlKey || e.metaKey) && e.key === listenKey) {
e.preventDefault();
onPress();
}
};
document.addEventListener("keydown", keydown);
return () => document.removeEventListener("keydown", keydown);
});
};
export interface PromptHotkeysConfig {
/** Function to call when Enter is pressed (confirm action) */
onConfirm?: () => void;
/** Function to call when Escape is pressed (cancel/close action) */
onCancel?: () => void;
/** Whether the hotkeys are enabled. Defaults to true */
enabled?: boolean;
/** Whether to ignore hotkeys when inside input/textarea elements. Defaults to true */
ignoreInputs?: boolean;
/** Whether the confirm action is disabled (e.g., form validation failed) */
confirmDisabled?: boolean;
}
/**
* Hook that provides standard prompt/dialog hotkey behavior:
* - Enter: Confirm/submit action
* - Escape: Cancel/close action
*/
export const usePromptHotkeys = ({
enabled = true,
onConfirm,
onCancel,
ignoreInputs = true,
confirmDisabled = false,
}: PromptHotkeysConfig) => {
useEffect(() => {
if (!enabled) return;
const findConfirmButton = (): HTMLButtonElement | null => {
const dialogContainers = document.querySelectorAll('[role="dialog"], [data-state="open"], .dialog-content');
for (const container of dialogContainers) {
const button = container.querySelector('[data-confirm-button]:not([disabled])') as HTMLButtonElement;
if (button) return button;
}
return document.querySelector('[data-confirm-button]:not([disabled])') as HTMLButtonElement;
};
const handleKeyDown = (e: KeyboardEvent) => {
if (ignoreInputs) {
const target = e.target as HTMLElement;
if (
target.tagName === "INPUT" ||
target.tagName === "TEXTAREA" ||
target.tagName === "SELECT" ||
target.isContentEditable
) {
return;
}
}
switch (e.key) {
case "Enter":
if (onConfirm && !confirmDisabled) {
e.preventDefault();
const confirmButton = findConfirmButton();
if (confirmButton) {
confirmButton.click();
} else {
onConfirm();
}
}
break;
case "Escape":
if (onCancel) {
e.preventDefault();
onCancel();
}
break;
}
};
document.addEventListener("keydown", handleKeyDown);
return () => document.removeEventListener("keydown", handleKeyDown);
}, [enabled, onConfirm, onCancel, ignoreInputs, confirmDisabled]);
};
export type WebhookIntegration = "Github" | "Gitlab";
export type WebhookIntegrations = {
[key: string]: WebhookIntegration;
};
const WEBHOOK_INTEGRATIONS_ATOM = atomWithStorage<WebhookIntegrations>(
"webhook-integrations-v2",
{}
);
export const useWebhookIntegrations = () => {
const [integrations, setIntegrations] = useAtom<WebhookIntegrations>(
WEBHOOK_INTEGRATIONS_ATOM
);
return {
integrations,
setIntegration: (provider: string, integration: WebhookIntegration) =>
setIntegrations({
...integrations,
[provider]: integration,
}),
};
};
export const getWebhookIntegration = (
integrations: WebhookIntegrations,
git_provider: string
) => {
return integrations[git_provider]
? integrations[git_provider]
: git_provider.includes("gitlab")
? "Gitlab"
: "Github";
};
export type WebhookIdOrName = "Id" | "Name";
const WEBHOOK_ID_OR_NAME_ATOM = atomWithStorage<WebhookIdOrName>(
"webhook-id-or-name-v1",
"Id"
);
export const useWebhookIdOrName = () => {
return useAtom<WebhookIdOrName>(WEBHOOK_ID_OR_NAME_ATOM);
};
export type Dimensions = { width: number; height: number };
export const useWindowDimensions = () => {
const [dimensions, setDimensions] = useState<Dimensions>({
width: 0,
height: 0,
});
useEffect(() => {
const callback = () => {
setDimensions({
width: window.screen.availWidth,
height: window.screen.availHeight,
});
};
callback();
window.addEventListener("resize", callback);
return () => {
window.removeEventListener("resize", callback);
};
}, []);
return dimensions;
};
const selected_resources = atomFamily((_: UsableResource) =>
atom<string[]>([])
);
export const useSelectedResources = (type: UsableResource) =>
useAtom(selected_resources(type));
const filter_by_update_available = atomWithStorage<boolean>(
"update-available-filter-v1",
false
);
export const useFilterByUpdateAvailable: () => [boolean, () => void] = () => {
const [filter, set] = useAtom<boolean>(filter_by_update_available);
return [filter, () => set(!filter)];
};
export const usePermissions = ({ type, id }: Types.ResourceTarget) => {
const user = useUser().data;
const perms = useRead("GetPermission", { target: { type, id } }).data as
| Types.PermissionLevelAndSpecifics
| Types.PermissionLevel
| undefined;
const info = useRead("GetCoreInfo", {}).data;
const ui_write_disabled = info?.ui_write_disabled ?? false;
const disable_non_admin_create = info?.disable_non_admin_create ?? false;
const level =
(perms && typeof perms === "string" ? perms : perms?.level) ??
Types.PermissionLevel.None;
const specific =
(perms && typeof perms === "string" ? [] : perms?.specific) ?? [];
const canWrite = !ui_write_disabled && level === Types.PermissionLevel.Write;
const canExecute = has_minimum_permissions(
{ level, specific },
Types.PermissionLevel.Execute
);
const [
specificLogs,
specificInspect,
specificTerminal,
specificAttach,
specificProcesses,
] = [
specific.includes(Types.SpecificPermission.Logs),
specific.includes(Types.SpecificPermission.Inspect),
specific.includes(Types.SpecificPermission.Terminal),
specific.includes(Types.SpecificPermission.Attach),
specific.includes(Types.SpecificPermission.Processes),
];
const canCreate =
type === "Server"
? user?.admin ||
(!disable_non_admin_create && user?.create_server_permissions)
: type === "Build"
? user?.admin ||
(!disable_non_admin_create && user?.create_build_permissions)
: type === "Alerter" ||
type === "Builder" ||
type === "Procedure" ||
type === "Action"
? user?.admin
: user?.admin || !disable_non_admin_create;
return {
canWrite,
canExecute,
canCreate,
specific,
specificLogs,
specificInspect,
specificTerminal,
specificAttach,
specificProcesses,
};
};
const templatesQueryBehaviorAtom =
atomWithStorage<Types.TemplatesQueryBehavior>(
"templates-query-behavior-v0",
Types.TemplatesQueryBehavior.Exclude
);
export const useTemplatesQueryBehavior = () =>
useAtom<Types.TemplatesQueryBehavior>(templatesQueryBehaviorAtom);
export type SettingsView =
| "Variables"
| "Tags"
| "Providers"
| "Users"
| "Profile";
const viewAtom = atomWithStorage<SettingsView>("settings-view-v2", "Variables");
export const useSettingsView = () => useAtom<SettingsView>(viewAtom);
/**
* Map of unique host ports to array of formatted full port map spec
* Formatted ex: 0.0.0.0:3000:3000/tcp
*/
export type PortsMap = { [host_port: string]: Array<Types.Port> };
export const useContainerPortsMap = (ports: Types.Port[]) => {
return useMemo(() => {
const map: PortsMap = {};
for (const port of ports) {
if (!port.PublicPort || !port.PrivatePort) continue;
if (map[port.PublicPort]) {
map[port.PublicPort].push(port);
} else {
map[port.PublicPort] = [port];
}
}
for (const key in map) {
map[key].sort();
}
return map;
}, [ports]);
};
/**
* A custom React hook that debounces a value, delaying its update until after
* a specified period of inactivity. This is useful for performance optimization
* in scenarios like search inputs, form validation, or API calls.
*/
export function useDebounce<T>(value: T, delay: number): T {
const [debouncedValue, setDebouncedValue] = useState<T>(value);
useEffect(() => {
const handler = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => {
clearTimeout(handler);
};
}, [value, delay]);
return debouncedValue;
}
+1 -6
View File
@@ -167,13 +167,8 @@ fn shell() -> &'static str {
String::from("/bin/bash")
} else if PathBuf::from("/usr/bin/bash").exists() {
String::from("/usr/bin/bash")
} else if PathBuf::from("/bin/sh").exists() {
String::from("/bin/sh")
} else if PathBuf::from("/usr/bin/sh").exists() {
String::from("/usr/bin/sh")
} else {
// try to use sh wherever it is on host by name.
String::from("sh")
String::from("/bin/sh")
}
})
}
-7
View File
@@ -24,13 +24,6 @@ cd ../docsite && yarn && \
cd ../client/core/ts && yarn
"""
[gen-resource-schema]
alias = "grs"
description = "generates resource toml definitions for edition autosuggest"
cmd = """
cargo xtask generate resource-schema --pretty --file=./ui/public/schema/resources.json
"""
[gen-client]
alias = "gc"
description = "generates typescript types and build the ts client"
+13 -15
View File
@@ -10,36 +10,34 @@
"build-client": "cd ../client/core/ts && yarn && yarn build && yarn link"
},
"dependencies": {
"@mantine/core": "^9.0.0",
"@mantine/form": "^9.0.0",
"@mantine/hooks": "^9.0.0",
"@mantine/notifications": "^9.0.0",
"@mantine/spotlight": "^9.0.0",
"@mantine/core": "^8.3.15",
"@mantine/form": "^8.3.15",
"@mantine/hooks": "^8.3.15",
"@mantine/notifications": "^8.3.15",
"@mantine/spotlight": "^8.3.15",
"@monaco-editor/react": "^4.7.0",
"@tanstack/react-query": "^5.96.1",
"@tanstack/react-query": "^5.90.21",
"@tanstack/react-table": "^8.21.3",
"@xterm/addon-fit": "^0.11.0",
"@xterm/xterm": "^6.0.0",
"ansi-to-html": "^0.7.2",
"jotai": "^2.19.0",
"jotai": "^2.18.0",
"jotai-family": "^1.0.1",
"jotai-location": "^0.6.2",
"lucide-react": "^1.7.0",
"mogh_auth_client": "^1.5.0",
"mogh_ui": "^0.5.1",
"lucide-react": "^1.6.0",
"monaco-editor": "^0.55.1",
"monaco-yaml": "^5.4.1",
"react": "^19.2.4",
"react-dom": "^19.2.4",
"react-minimal-pie-chart": "^9.1.2",
"react-router-dom": "^7.14.0",
"react-router-dom": "^7.13.0",
"react-xtermjs": "^1.0.10",
"recharts": "^3.8.1",
"sanitize-html": "^2.17.2",
"recharts": "^3.7.0",
"sanitize-html": "^2.17.1",
"shell-quote": "^1.8.3"
},
"devDependencies": {
"@types/node": "^25.5.0",
"@types/node": "^25.3.0",
"@types/react": "^19.2.14",
"@types/react-dom": "^19.2.3",
"@types/sanitize-html": "^2.16.0",
@@ -49,7 +47,7 @@
"postcss": "^8.5.6",
"postcss-preset-mantine": "^1.18.0",
"postcss-simple-vars": "^7.0.1",
"sass-embedded": "^1.99.0",
"sass-embedded": "^1.97.3",
"typescript": "^6.0.2",
"vite": "^8.0.2"
},
+8 -34
View File
@@ -607,7 +607,6 @@ export interface ImageRegistryConfig {
export interface SystemCommand {
path?: string;
command?: string;
shell_mode?: boolean;
}
/** The build configuration. */
export interface BuildConfig {
@@ -1569,8 +1568,6 @@ export declare enum DeploymentState {
Created = "created",
/** Server mode only. Container is in restart loop */
Restarting = "restarting",
/** Server mode only. Container is in the process of stopping */
Stopping = "stopping",
/** Server mode only. Container is being removed */
Removing = "removing",
/** Server mode only. Container is paused */
@@ -2617,12 +2614,6 @@ export interface StackConfig {
* Komodo will redeploy the whole Stack (all services).
*/
auto_update_all_services?: boolean;
/**
* Ignore certain services during Global Auto Update polling.
* Services listed here are skipped only in the global auto-update flow.
* Manual checks still include all services.
*/
auto_update_skip_services?: string[];
/** Whether to run `docker compose down` before `compose up`. */
destroy_before_deploy?: boolean;
/** Whether to skip secret interpolation into the stack environment variables. */
@@ -3082,7 +3073,6 @@ export declare enum ContainerStateStatusEnum {
Paused = "paused",
Restarting = "restarting",
Exited = "exited",
Stopping = "stopping",
Removing = "removing",
Dead = "dead",
Empty = ""
@@ -3199,7 +3189,8 @@ export interface RestartPolicy {
/** If `on-failure` is used, the number of times to retry before giving up. */
MaximumRetryCount?: I64;
}
export declare enum MountType {
export declare enum MountTypeEnum {
Empty = "",
Bind = "bind",
Volume = "volume",
Image = "image",
@@ -3265,7 +3256,7 @@ export interface Mount {
* - `tmpfs` Create a tmpfs with the given options. The mount source cannot be specified for tmpfs. - `npipe` Mounts a named pipe from the host into the container. Must exist prior to creating the container.
* - `cluster` a Swarm cluster volume
*/
Type?: MountType;
Type?: MountTypeEnum;
/** Whether the mount should be read-only. */
ReadOnly?: boolean;
/** The consistency requirement for the mount: `default`, `consistent`, `cached`, or `delegated`. */
@@ -3433,7 +3424,7 @@ export interface GraphDriverData {
/** MountPoint represents a mount point configuration inside the container. This is used for reporting the mountpoints in use by a container. */
export interface MountPoint {
/** The mount type: - `bind` a mount of a file or directory from the host into the container. - `volume` a docker volume with the given `Name`. - `tmpfs` a `tmpfs`. - `npipe` a named pipe from the host into the container. - `cluster` a Swarm cluster volume */
Type?: string;
Type?: MountTypeEnum;
/** Name is the name reference to the underlying data defined by `Source` e.g., the volume name. */
Name?: string;
/** Source location of the mount. For volumes, this contains the storage location of the volume (within `/var/lib/docker/volumes/`). For bind-mounts, and `npipe`, this contains the source (host) part of the bind-mount. For `tmpfs` mount points, this field is empty. */
@@ -4307,10 +4298,7 @@ export interface ClusterVolumeSpecAccessModeSecrets {
/** Secret is the swarm Secret object from which to read data. This can be a Secret name or ID. The Secret data is retrieved by swarm and used as the value of the key-value pair passed to the plugin. */
Secret?: string;
}
/** A map of topological domains to topological segments. For in depth details, see documentation for the Topology object in the CSI specification. */
export interface Topology {
Segments?: Record<string, string>;
}
export type Topology = Record<string, PortBinding[]>;
/** Requirements for the accessible topology of the volume. These fields are optional. For an in-depth description of what these fields mean, see the CSI specification. */
export interface ClusterVolumeSpecAccessModeAccessibilityRequirements {
/** A list of required topologies, at least one of which the volume must be accessible from. */
@@ -6575,8 +6563,7 @@ export interface CreateOnboardingKey {
expires?: I64;
/**
* Optionally specify an existing private key, otherwise
* generate fresh key. This key is not stored directly,
* only the public key.
* generate fresh key.
*/
private_key?: string;
/** Default tags to apply to Servers created using this key. */
@@ -7145,31 +7132,18 @@ export interface UserGroupToml {
}
/** Specifies resources to sync on Komodo */
export interface ResourcesToml {
/** Declare a swarm */
swarms?: ResourceToml<_PartialSwarmConfig>[];
/** Declare a server */
servers?: ResourceToml<_PartialServerConfig>[];
/** Declare a stack */
stacks?: ResourceToml<_PartialStackConfig>[];
/** Declare a deployment */
deployments?: ResourceToml<_PartialDeploymentConfig>[];
/** Declare a build */
stacks?: ResourceToml<_PartialStackConfig>[];
builds?: ResourceToml<_PartialBuildConfig>[];
/** Declare a repo */
repos?: ResourceToml<_PartialRepoConfig>[];
/** Declare a procedure */
procedures?: ResourceToml<_PartialProcedureConfig>[];
/** Declare an action */
actions?: ResourceToml<_PartialActionConfig>[];
/** Declare an alerter */
alerters?: ResourceToml<_PartialAlerterConfig>[];
/** Declare a builder */
builders?: ResourceToml<_PartialBuilderConfig>[];
/** Declare a resource sync */
resource_syncs?: ResourceToml<_PartialResourceSyncConfig>[];
/** Declare a user group */
user_groups?: UserGroupToml[];
/** Declare a variable */
variables?: Variable[];
}
/**
@@ -7434,7 +7408,7 @@ export interface GetCoreInfoResponse {
enable_fancy_toml: boolean;
/** TZ identifier Core is using, if manually set. */
timezone: string;
/** Public key for Core / Periphery authentication. */
/** Default public key allowing this Core to authenticate to Periphery agents. */
public_key: string;
}
/** Get a specific deployment by name or id. Response: [Deployment]. */
+10 -12
View File
@@ -253,8 +253,6 @@ export var DeploymentState;
DeploymentState["Created"] = "created";
/** Server mode only. Container is in restart loop */
DeploymentState["Restarting"] = "restarting";
/** Server mode only. Container is in the process of stopping */
DeploymentState["Stopping"] = "stopping";
/** Server mode only. Container is being removed */
DeploymentState["Removing"] = "removing";
/** Server mode only. Container is paused */
@@ -420,7 +418,6 @@ export var ContainerStateStatusEnum;
ContainerStateStatusEnum["Paused"] = "paused";
ContainerStateStatusEnum["Restarting"] = "restarting";
ContainerStateStatusEnum["Exited"] = "exited";
ContainerStateStatusEnum["Stopping"] = "stopping";
ContainerStateStatusEnum["Removing"] = "removing";
ContainerStateStatusEnum["Dead"] = "dead";
ContainerStateStatusEnum["Empty"] = "";
@@ -441,15 +438,16 @@ export var RestartPolicyNameEnum;
RestartPolicyNameEnum["UnlessStopped"] = "unless-stopped";
RestartPolicyNameEnum["OnFailure"] = "on-failure";
})(RestartPolicyNameEnum || (RestartPolicyNameEnum = {}));
export var MountType;
(function (MountType) {
MountType["Bind"] = "bind";
MountType["Volume"] = "volume";
MountType["Image"] = "image";
MountType["Tmpfs"] = "tmpfs";
MountType["Npipe"] = "npipe";
MountType["Cluster"] = "cluster";
})(MountType || (MountType = {}));
export var MountTypeEnum;
(function (MountTypeEnum) {
MountTypeEnum["Empty"] = "";
MountTypeEnum["Bind"] = "bind";
MountTypeEnum["Volume"] = "volume";
MountTypeEnum["Image"] = "image";
MountTypeEnum["Tmpfs"] = "tmpfs";
MountTypeEnum["Npipe"] = "npipe";
MountTypeEnum["Cluster"] = "cluster";
})(MountTypeEnum || (MountTypeEnum = {}));
export var MountBindOptionsPropagationEnum;
(function (MountBindOptionsPropagationEnum) {
MountBindOptionsPropagationEnum["Empty"] = "";
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -4,7 +4,7 @@ import { Suspense } from "react";
import { Outlet } from "react-router-dom";
import Topbar from "@/app/topbar";
import Sidebar from "@/app/sidebar";
import { LoadingScreen } from "mogh_ui";
import LoadingScreen from "@/ui/loading-screen";
import UpdateDetails from "@/components/updates/details";
import AlertDetails from "@/components/alerts/details";
+1 -1
View File
@@ -1,4 +1,4 @@
import { ICONS } from "@/lib/icons";
import { ICONS } from "@/theme/icons";
import { usableResourcePath } from "@/lib/utils";
import { SIDEBAR_RESOURCES } from "@/resources";
import { Button, Divider, ScrollArea, Stack, Text } from "@mantine/core";
+1 -1
View File
@@ -1,5 +1,5 @@
import { useRead } from "@/lib/hooks";
import { ICONS } from "@/lib/icons";
import { ICONS } from "@/theme/icons";
import { ActionIcon, Box, Center, Menu } from "@mantine/core";
import { useDisclosure } from "@mantine/hooks";
import AlertList from "@/components/alerts/list";
+6 -6
View File
@@ -9,8 +9,8 @@ import {
SimpleGrid,
Text,
} from "@mantine/core";
import { Link } from "react-router-dom";
import { ThemeToggle } from "mogh_ui";
import { useNavigate } from "react-router-dom";
import ThemeToggle from "@/ui/theme-toggle";
import UserDropdown from "@/app/topbar/user-dropdown";
import TopbarUpdates from "@/app/topbar/updates";
import OmniSearch from "@/app/topbar/omni-search";
@@ -27,6 +27,7 @@ const Topbar = ({
opened: boolean;
toggle: () => void;
}) => {
const nav = useNavigate();
const version = useRead("GetVersion", {}, { refetchInterval: 30_000 }).data
?.version;
return (
@@ -45,22 +46,21 @@ const Topbar = ({
{/** LEFT AREA */}
<Group gap="xs" wrap="nowrap" w="fit-content">
<Burger opened={opened} onClick={toggle} hiddenFrom="sm" size="sm" />
<ActionIcon
variant="subtle"
renderRoot={(props) => <Link to="/" {...props} />}
onClick={() => nav("/")}
size="lg"
hiddenFrom="md"
>
<img src="/mogh-512x512.png" width={32} alt="moghtech" />
</ActionIcon>
<Button
variant="subtle"
renderRoot={(props) => <Link to="/" {...props} />}
c="inherit"
leftSection={
<img src="/mogh-512x512.png" width={32} alt="moghtech" />
}
onClick={() => nav("/")}
size="lg"
visibleFrom="md"
>
+1 -2
View File
@@ -1,4 +1,4 @@
import { useSettingsView } from "@/lib/hooks";
import { useSettingsView, useShiftKeyListener } from "@/lib/hooks";
import {
ActionIcon,
Divider,
@@ -10,7 +10,6 @@ import {
} from "@mantine/core";
import { useDisclosure } from "@mantine/hooks";
import { Keyboard } from "lucide-react";
import { useShiftKeyListener } from "mogh_ui";
import { useNavigate } from "react-router-dom";
export default function KeyboardShortcuts() {
+14 -3
View File
@@ -1,9 +1,20 @@
import { ButtonLink, ButtonLinkProps } from "mogh_ui";
import { Button, ButtonProps } from "@mantine/core";
import { Link } from "react-router-dom";
export interface TopbarLinkProps extends ButtonLinkProps {
export interface TopbarLinkProps extends ButtonProps {
to: string;
}
export default function TopbarLink({ to, ...props }: TopbarLinkProps) {
return <ButtonLink visibleFrom="md" to={to} {...props} />;
return (
<Button
visibleFrom="md"
variant="subtle"
px="xs"
fz="sm"
className="hover-underline"
renderRoot={(props) => <Link to={to} target="_blank" {...props} />}
{...props}
/>
);
}
+1 -1
View File
@@ -6,7 +6,7 @@ import {
useSettingsView,
useUser,
} from "@/lib/hooks";
import { ICONS } from "@/lib/icons";
import { ICONS } from "@/theme/icons";
import { terminalLink, usableResourcePath } from "@/lib/utils";
import { RESOURCE_TARGETS, ResourceComponents } from "@/resources";
import {
+2 -3
View File
@@ -1,8 +1,8 @@
import { ActionIcon, Badge, Button, Group } from "@mantine/core";
import { Spotlight, spotlight } from "@mantine/spotlight";
import { useOmniSearch } from "./hooks";
import { ICONS } from "@/lib/icons";
import { useShiftKeyListener } from "mogh_ui";
import { ICONS } from "@/theme/icons";
import { useShiftKeyListener } from "@/lib/hooks";
import classes from "./index.module.scss";
export default function OmniSearch({}: {}) {
@@ -40,7 +40,6 @@ export default function OmniSearch({}: {}) {
query={search}
onQueryChange={setSearch}
clearQueryOnClose={false}
radius="sm"
>
<Spotlight.Search
leftSection={<ICONS.Search size="1.3rem" />}
+1 -1
View File
@@ -1,5 +1,5 @@
import { useRead, useUser, useUserInvalidate, useWrite } from "@/lib/hooks";
import { ICONS } from "@/lib/icons";
import { ICONS } from "@/theme/icons";
import {
ActionIcon,
Center,
+2 -2
View File
@@ -21,7 +21,7 @@ import { useMemo, useState } from "react";
import { useNavigate } from "react-router-dom";
import { MoghAuth } from "komodo_client";
import { useRead, useUser, useUserInvalidate } from "@/lib/hooks";
import { hexColorByIntention } from "mogh_ui";
import { hexColorByIntention } from "@/lib/color";
export default function UserDropdown() {
const [_, setRerender] = useState(false);
@@ -104,7 +104,7 @@ export default function UserDropdown() {
onClick={() => {
setOpen(false);
nav(
`/login?${new URLSearchParams({ backto: `${location.pathname}${location.search}`, disableAutoLogin: "true" })}`,
`/login?${new URLSearchParams({ backto: `${location.pathname}${location.search}` })}`,
);
}}
>
+1 -1
View File
@@ -1,8 +1,8 @@
import { hexColorByIntention } from "@/lib/color";
import { useWebsocketConnected, useWebsocketReconnect } from "@/lib/socket";
import { ActionIcon, Box, HoverCard, Text } from "@mantine/core";
import { notifications } from "@mantine/notifications";
import { Circle } from "lucide-react";
import { hexColorByIntention } from "mogh_ui";
export default function WebsocketStatus() {
const connected = useWebsocketConnected();
+3 -3
View File
@@ -1,12 +1,12 @@
import { BoxProps, Flex, FlexProps, Group, Stack } from "@mantine/core";
import { Types } from "komodo_client";
import { AlertTriangle, Check } from "lucide-react";
import { fmtDate, fmtUpperCamelcase } from "mogh_ui";
import { ICONS } from "@/lib/icons";
import { fmtDate, fmtUpperCamelcase } from "@/lib/formatting";
import { ICONS } from "@/theme/icons";
import { useAlertDetails } from "./details";
import AlertLevel from "./level";
import ResourceLink from "@/resources/link";
import { hexColorByIntention } from "mogh_ui";
import { hexColorByIntention } from "@/lib/color";
export default function AlertCard({
alert,
+10 -6
View File
@@ -1,16 +1,20 @@
import { fmtDateWithMinutes, fmtDuration, fmtUpperCamelcase } from "mogh_ui";
import {
fmtDateWithMinutes,
fmtDuration,
fmtUpperCamelcase,
} from "@/lib/formatting";
import { useInvalidate, useRead, useUser, useWrite } from "@/lib/hooks";
import { ResourceComponents, UsableResource } from "@/resources";
import { ActionIcon, Drawer, Group, Stack, Text } from "@mantine/core";
import { ICONS } from "@/lib/icons";
import { ICONS } from "@/theme/icons";
import { Clock, Link2 } from "lucide-react";
import { CopyButton } from "mogh_ui";
import { MonacoEditor } from "mogh_ui";
import { LoadingScreen } from "mogh_ui";
import CopyButton from "@/ui/copy-button";
import { MonacoEditor } from "@/components/monaco";
import LoadingScreen from "@/ui/loading-screen";
import { atom, useAtom } from "jotai";
import ResourceLink from "@/resources/link";
import { notifications } from "@mantine/notifications";
import { ConfirmButton } from "mogh_ui";
import ConfirmButton from "@/ui/confirm-button";
import { To, useLocation, useNavigate } from "react-router-dom";
const alertDetailsAtom = atom<string>();
+1 -1
View File
@@ -1,5 +1,5 @@
import { alertLevelIntention } from "@/lib/color";
import { StatusBadge } from "mogh_ui";
import StatusBadge from "@/ui/status-badge";
import { Types } from "komodo_client";
export default function AlertLevel({
+1 -1
View File
@@ -2,7 +2,7 @@ import { useRead } from "@/lib/hooks";
import { Types } from "komodo_client";
import AlertCard from "./card";
import { Button, Box, BoxProps, Stack } from "@mantine/core";
import { ICONS } from "@/lib/icons";
import { ICONS } from "@/theme/icons";
import { Link } from "react-router-dom";
export interface AlertListProps extends BoxProps {
+5 -13
View File
@@ -1,5 +1,6 @@
import { useInvalidate, useWrite } from "@/lib/hooks";
import { ICONS } from "@/lib/icons";
import { useInvalidate, useManageAuth, useWrite } from "@/lib/hooks";
import { ICONS } from "@/theme/icons";
import CopyText from "@/ui/copy-text";
import {
Button,
Group,
@@ -12,7 +13,6 @@ import {
import { useDisclosure } from "@mantine/hooks";
import { Types } from "komodo_client";
import { useState } from "react";
import { CopyText, useManageAuth } from "mogh_ui";
const ONE_DAY_MS = 1000 * 60 * 60 * 24;
type ExpiresOptions = "90 days" | "180 days" | "1 year" | "Never";
@@ -133,20 +133,12 @@ export default function NewApiKey({ userId }: { userId?: string }) {
<Group justify="space-between" wrap="nowrap">
<Text>Key</Text>
<CopyText
content={created.key}
label="API key"
w={{ base: 200, lg: 250 }}
/>
<CopyText content={created.key} label="API key" w={{ base: 200, lg: 250 }} />
</Group>
<Group justify="space-between" wrap="nowrap">
<Text>Secret</Text>
<CopyText
content={created.secret}
label="API secret"
w={{ base: 200, lg: 250 }}
/>
<CopyText content={created.secret} label="API secret" w={{ base: 200, lg: 250 }} />
</Group>
<Group justify="end" onClick={close}>
+4 -3
View File
@@ -1,8 +1,8 @@
import { ICONS } from "@/lib/icons";
import { Section, SectionProps, useManageAuth } from "mogh_ui";
import { ICONS } from "@/theme/icons";
import Section, { SectionProps } from "@/ui/section";
import NewApiKey from "./new";
import ApiKeysTable from "./table";
import { useInvalidate, useRead, useWrite } from "@/lib/hooks";
import { useInvalidate, useManageAuth, useRead, useWrite } from "@/lib/hooks";
import { notifications } from "@mantine/notifications";
import { Box } from "@mantine/core";
@@ -47,6 +47,7 @@ export default function ApiKeysSection({
isPending={isPending}
title="API Keys"
titleFz="h3"
icon={<ICONS.Key size="1.2rem" />}
titleRight={
<Box ml="md">
+4 -4
View File
@@ -1,7 +1,7 @@
import { ICONS } from "@/lib/icons";
import { ConfirmButton } from "mogh_ui";
import { CopyText } from "mogh_ui";
import { DataTable } from "mogh_ui";
import { ICONS } from "@/theme/icons";
import ConfirmButton from "@/ui/confirm-button";
import CopyText from "@/ui/copy-text";
import { DataTable } from "@/ui/data-table";
import { Text } from "@mantine/core";
import { Types } from "komodo_client";
+3 -4
View File
@@ -1,8 +1,8 @@
import { fmtUpperCamelcase } from "mogh_ui";
import { fmtUpperCamelcase } from "@/lib/formatting";
import { useExecute, useSelectedResources, useWrite } from "@/lib/hooks";
import { usableResourceExecuteKey } from "@/lib/utils";
import { sendCopyNotification, usableResourceExecuteKey } from "@/lib/utils";
import { UsableResource } from "@/resources";
import { ICONS } from "@/lib/icons";
import { ICONS } from "@/theme/icons";
import {
Box,
Button,
@@ -20,7 +20,6 @@ import {
import { Types } from "komodo_client";
import { ChevronDown } from "lucide-react";
import { FC, useState } from "react";
import { sendCopyNotification } from "mogh_ui";
type Request = Types.ExecuteRequest["type"] | Types.WriteRequest["type"];
@@ -1,5 +1,5 @@
import { useRead } from "@/lib/hooks";
import { ConfigItem } from "mogh_ui";
import { ConfigItem } from "@/ui/config/item";
import { Select, SelectProps } from "@mantine/core";
export interface AccountSelectorProps extends Omit<SelectProps, "onSelect"> {
+3 -4
View File
@@ -1,8 +1,7 @@
import { useRead } from "@/lib/hooks";
import { filterBySplit } from "mogh_ui";
import { useRead, useSearchCombobox } from "@/lib/hooks";
import { filterBySplit } from "@/lib/utils";
import { Button, Combobox } from "@mantine/core";
import { ICONS } from "@/lib/icons";
import { useSearchCombobox } from "mogh_ui";
import { ICONS } from "@/theme/icons";
export interface AddExtraArgProps {
type: "Deployment" | "Build" | "Stack" | "StackBuild";

Some files were not shown because too many files have changed in this diff Show More