refactor(integrations): make chat integrations Slack-only

This commit is contained in:
Bryan Helmkamp 2026-05-09 11:43:16 -04:00
parent 1ff30ea03c
commit 8ad14faa17
No known key found for this signature in database
27 changed files with 180 additions and 246 deletions

View file

@ -84,7 +84,7 @@ function sampleSettings({
},
},
notifications: {},
interviews: { provider: null, slack: null, discord: null, teams: null },
interviews: { provider: null, slack: null },
agent: { permissions: null, mcps: {} },
hooks: [],
scm: { provider: null, owner: null, repository: null, github: null },

View file

@ -108,7 +108,7 @@ The new design must optimize for:
- R62. Sandbox config must remain provider-specific because provider differences are too large to hide behind one flat abstraction.
- R63. Model config must remain intentionally provider-neutral. It should not grow provider-specific subtables. `run.model.fallbacks` is a single ordered array of model references. Each entry may be a bare provider token such as `openai`, a bare model alias or model id such as `gpt-5.4`, or a qualified reference such as `gemini/gemini-flash`. Bare references are allowed only when unambiguous. Ambiguous bare references must hard-error and require qualification. A bare provider token means “choose the best matching model from that provider.”
- R64. SCM config must be provider-neutral at the core (`[run.scm]`) with room for provider-specific nested tables such as `[run.scm.github]` only where necessary.
- R65. Chat platforms such as Slack, Discord, and Teams are integrations. Their server-owned setup lives under `[server.integrations.<provider>]`; run behavior lives under `[run.notifications.*]` and `[run.interviews]`.
- R65. Slack is the chat integration. Its server-owned setup lives under `[server.integrations.slack]`; run behavior lives under `[run.notifications.*]` and `[run.interviews]`.
- R66. Object-store-backed domains must use a shared pattern: a small provider-neutral envelope plus provider-specific nested tables.
- R67. For local object-store providers, default to `server.storage.root`, but allow explicit local override roots when needed.

View file

@ -75,7 +75,7 @@ This refactor is centered on four seams:
- notification route surface first pass:
- route envelope fields are `enabled`, `provider`, and `events`
- provider-specific destination fields live under `[run.notifications.<name>.<provider>]`
- first-pass chat destinations for Slack, Discord, and Teams use `channel`
- first-pass Slack destinations use `channel`
- duration parser first pass:
- one shared parser accepts a single unit suffix per value: `ms`, `s`, `m`, `h`, or `d`
- composed values like `1h30m` are not supported in first pass; use the smallest needed unit instead

View file

@ -560,7 +560,7 @@ These are lessons learned during Stages 15. Save yourself the pain.
enumerated list of known-provider subfields instead (that's why
`RunSandboxLayer`, `NotificationRouteLayer`, `InterviewsLayer`,
`RunScmLayer`, `ServerIntegrationsLayer`, etc. have explicit
`github`/`slack`/`discord`/`teams`/`local`/`s3` fields). Adding a new
`github`/`slack`/`local`/`s3` fields). Adding a new
provider means adding a new field.
## Repo conventions you'll hit

View file

@ -7771,16 +7771,12 @@ components:
ServerIntegrationsSettings:
type: object
required: [github, slack, discord, teams]
required: [github, slack]
properties:
github:
$ref: "#/components/schemas/GithubIntegrationSettings"
slack:
$ref: "#/components/schemas/SlackIntegrationSettings"
discord:
$ref: "#/components/schemas/DiscordIntegrationSettings"
teams:
$ref: "#/components/schemas/TeamsIntegrationSettings"
GithubIntegrationSettings:
type: object
@ -7820,20 +7816,6 @@ components:
default_channel:
type: ["string", "null"]
DiscordIntegrationSettings:
type: object
required: [enabled]
properties:
enabled:
type: boolean
TeamsIntegrationSettings:
type: object
required: [enabled]
properties:
enabled:
type: boolean
IntegrationWebhooksSettings:
type: object
required: [strategy, ip_allowlist]
@ -8218,7 +8200,7 @@ components:
NotificationRouteSettings:
type: object
required: [enabled, provider, events, slack, discord, teams]
required: [enabled, provider, events, slack]
properties:
enabled:
type: boolean
@ -8232,14 +8214,6 @@ components:
oneOf:
- $ref: "#/components/schemas/NotificationProviderSettings"
- type: "null"
discord:
oneOf:
- $ref: "#/components/schemas/NotificationProviderSettings"
- type: "null"
teams:
oneOf:
- $ref: "#/components/schemas/NotificationProviderSettings"
- type: "null"
NotificationProviderSettings:
type: object
@ -8250,7 +8224,7 @@ components:
RunInterviewsSettings:
type: object
required: [provider, slack, discord, teams]
required: [provider, slack]
properties:
provider:
type: ["string", "null"]
@ -8258,14 +8232,6 @@ components:
oneOf:
- $ref: "#/components/schemas/InterviewProviderSettings"
- type: "null"
discord:
oneOf:
- $ref: "#/components/schemas/InterviewProviderSettings"
- type: "null"
teams:
oneOf:
- $ref: "#/components/schemas/InterviewProviderSettings"
- type: "null"
InterviewProviderSettings:
type: object

View file

@ -315,16 +315,6 @@ fn main() {
"fabro_types::settings::server::SlackIntegrationSettings",
&[],
),
(
"DiscordIntegrationSettings",
"fabro_types::settings::server::DiscordIntegrationSettings",
&[],
),
(
"TeamsIntegrationSettings",
"fabro_types::settings::server::TeamsIntegrationSettings",
&[],
),
(
"IntegrationWebhooksSettings",
"fabro_types::settings::server::IntegrationWebhooksSettings",

View file

@ -16,13 +16,13 @@ mod generated {
pub mod types {
pub use fabro_model::{Model, ModelCosts, ModelFeatures, ModelLimits, ModelTestMode, Provider};
pub use fabro_types::settings::server::{
DiscordIntegrationSettings, GithubIntegrationSettings, GithubIntegrationStrategy,
IntegrationWebhooksSettings, IpAllowEntry, LogDestination, ObjectStoreSettings,
ServerApiSettings, ServerArtifactsSettings, ServerAuthGithubSettings, ServerAuthMethod,
ServerAuthSettings, ServerIntegrationsSettings, ServerIpAllowlistOverrideSettings,
ServerIpAllowlistSettings, ServerListenSettings, ServerLoggingSettings,
ServerSchedulerSettings, ServerSlateDbSettings, ServerStorageSettings, ServerWebSettings,
SlackIntegrationSettings, TeamsIntegrationSettings, WebhookStrategy,
GithubIntegrationSettings, GithubIntegrationStrategy, IntegrationWebhooksSettings,
IpAllowEntry, LogDestination, ObjectStoreSettings, ServerApiSettings,
ServerArtifactsSettings, ServerAuthGithubSettings, ServerAuthMethod, ServerAuthSettings,
ServerIntegrationsSettings, ServerIpAllowlistOverrideSettings, ServerIpAllowlistSettings,
ServerListenSettings, ServerLoggingSettings, ServerSchedulerSettings,
ServerSlateDbSettings, ServerStorageSettings, ServerWebSettings, SlackIntegrationSettings,
WebhookStrategy,
};
pub use fabro_types::settings::{FeaturesNamespace, ServerNamespace};
pub use fabro_types::status::{

View file

@ -945,10 +945,8 @@ fn attach_json_errors_without_prompting_for_human_input() {
}
},
"interviews": {
"discord": null,
"provider": null,
"slack": null,
"teams": null
"slack": null
},
"metadata": {},
"model": {

View file

@ -29,12 +29,11 @@ pub use run::{
ScmGitHubLayer, StringOrSplice,
};
pub use server::{
DiscordIntegrationLayer, GithubIntegrationLayer, IntegrationWebhooksLayer,
ObjectStoreLocalLayer, ObjectStoreS3Layer, ServerApiLayer, ServerArtifactsLayer,
ServerAuthGithubLayer, ServerAuthLayer, ServerIntegrationsLayer, ServerIpAllowlistLayer,
ServerIpAllowlistOverrideLayer, ServerLayer, ServerListenLayer, ServerLoggingLayer,
ServerSchedulerLayer, ServerSlateDbLayer, ServerStorageLayer, ServerWebLayer,
SlackIntegrationLayer, TeamsIntegrationLayer,
GithubIntegrationLayer, IntegrationWebhooksLayer, ObjectStoreLocalLayer, ObjectStoreS3Layer,
ServerApiLayer, ServerArtifactsLayer, ServerAuthGithubLayer, ServerAuthLayer,
ServerIntegrationsLayer, ServerIpAllowlistLayer, ServerIpAllowlistOverrideLayer, ServerLayer,
ServerListenLayer, ServerLoggingLayer, ServerSchedulerLayer, ServerSlateDbLayer,
ServerStorageLayer, ServerWebLayer, SlackIntegrationLayer,
};
pub(crate) use settings::SettingsLayer;
pub use workflow::WorkflowLayer;

View file

@ -334,13 +334,9 @@ pub struct NotificationRouteLayer {
/// Raw Fabro event names. Splice marker supported at layering time.
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub events: Vec<StringOrSplice>,
/// Provider-specific destination subtables. First-pass chat providers.
/// Provider-specific destination subtables.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub slack: Option<NotificationProviderLayer>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub discord: Option<NotificationProviderLayer>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub teams: Option<NotificationProviderLayer>,
}
/// A single string array entry that may be the splice marker.
@ -386,10 +382,6 @@ pub struct InterviewsLayer {
pub provider: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub slack: Option<InterviewProviderLayer>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub discord: Option<InterviewProviderLayer>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub teams: Option<InterviewProviderLayer>,
}
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]

View file

@ -189,21 +189,15 @@ pub struct ServerLoggingLayer {
pub destination: Option<LogDestination>,
}
/// `[server.integrations.<provider>]` — cohesive integration surface for chat
/// platforms and git providers (GitHub App, webhooks, etc.). First-pass
/// integrations enumerate known providers rather than using a flatten-HashMap
/// shape so strict unknown-field validation still holds.
/// `[server.integrations.<provider>]` — cohesive integration surface for Slack
/// and git providers (GitHub App, webhooks, etc.).
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, fabro_macros::Combine)]
#[serde(deny_unknown_fields)]
pub struct ServerIntegrationsLayer {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub github: Option<GithubIntegrationLayer>,
pub github: Option<GithubIntegrationLayer>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub slack: Option<SlackIntegrationLayer>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub discord: Option<DiscordIntegrationLayer>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub teams: Option<TeamsIntegrationLayer>,
pub slack: Option<SlackIntegrationLayer>,
}
/// `[server.integrations.github]` — GitHub App, credentials, and inbound
@ -235,22 +229,6 @@ pub struct SlackIntegrationLayer {
pub default_channel: Option<InterpString>,
}
/// `[server.integrations.discord]` — Discord workspace configuration.
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, fabro_macros::Combine)]
#[serde(deny_unknown_fields)]
pub struct DiscordIntegrationLayer {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub enabled: Option<bool>,
}
/// `[server.integrations.teams]` — Microsoft Teams configuration.
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, fabro_macros::Combine)]
#[serde(deny_unknown_fields)]
pub struct TeamsIntegrationLayer {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub enabled: Option<bool>,
}
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, fabro_macros::Combine)]
#[serde(deny_unknown_fields)]
pub struct IntegrationWebhooksLayer {

View file

@ -40,19 +40,18 @@ pub use input_overrides::{InputOverrideParseError, parse_input_overrides};
pub use layers::{
CliAuthLayer, CliExecAgentLayer, CliExecLayer, CliExecModelLayer, CliLayer, CliLoggingLayer,
CliOutputLayer, CliTargetLayer, CliUpdatesLayer, DaytonaDockerfileLayer, DaytonaSandboxLayer,
DaytonaSnapshotLayer, DiscordIntegrationLayer, DockerSandboxLayer, FeaturesLayer,
GitAuthorLayer, GithubIntegrationLayer, HookAgentMarker, HookEntry, HookTlsMode,
IntegrationWebhooksLayer, InterviewProviderLayer, InterviewsLayer, LogFilter, McpEntryLayer,
MergeMap, ModelRefOrSplice, NotificationProviderLayer, NotificationRouteLayer,
ObjectStoreLocalLayer, ObjectStoreS3Layer, PrepareStep, ProjectLayer, ReplaceMap,
RunAgentLayer, RunArtifactsLayer, RunCheckpointLayer, RunExecutionLayer, RunGitLayer,
RunGoalLayer, RunIntegrationsGithubLayer, RunIntegrationsLayer, RunLayer, RunModelLayer,
RunPrepareLayer, RunPullRequestLayer, RunSandboxLayer, RunScmLayer, ScmGitHubLayer,
ServerApiLayer, ServerArtifactsLayer, ServerAuthGithubLayer, ServerAuthLayer,
DaytonaSnapshotLayer, DockerSandboxLayer, FeaturesLayer, GitAuthorLayer,
GithubIntegrationLayer, HookAgentMarker, HookEntry, HookTlsMode, IntegrationWebhooksLayer,
InterviewProviderLayer, InterviewsLayer, LogFilter, McpEntryLayer, MergeMap, ModelRefOrSplice,
NotificationProviderLayer, NotificationRouteLayer, ObjectStoreLocalLayer, ObjectStoreS3Layer,
PrepareStep, ProjectLayer, ReplaceMap, RunAgentLayer, RunArtifactsLayer, RunCheckpointLayer,
RunExecutionLayer, RunGitLayer, RunGoalLayer, RunIntegrationsGithubLayer, RunIntegrationsLayer,
RunLayer, RunModelLayer, RunPrepareLayer, RunPullRequestLayer, RunSandboxLayer, RunScmLayer,
ScmGitHubLayer, ServerApiLayer, ServerArtifactsLayer, ServerAuthGithubLayer, ServerAuthLayer,
ServerIntegrationsLayer, ServerIpAllowlistLayer, ServerIpAllowlistOverrideLayer, ServerLayer,
ServerListenLayer, ServerLoggingLayer, ServerSchedulerLayer, ServerSlateDbLayer,
ServerStorageLayer, ServerWebLayer, SlackIntegrationLayer, StickyMap, StringOrSplice,
TeamsIntegrationLayer, WorkflowLayer,
WorkflowLayer,
};
pub(crate) use layers::{Combine, SettingsLayer};
pub use logging::{resolve_log_destination, resolve_log_destination_with_env};

View file

@ -242,8 +242,6 @@ fn resolve_notification_route(route: &NotificationRouteLayer) -> NotificationRou
})
.collect(),
slack: route.slack.as_ref().map(resolve_notification_provider),
discord: route.discord.as_ref().map(resolve_notification_provider),
teams: route.teams.as_ref().map(resolve_notification_provider),
}
}
@ -263,8 +261,6 @@ fn resolve_interviews(interviews: Option<&InterviewsLayer>) -> RunInterviewsSett
RunInterviewsSettings {
provider: interviews.provider.clone(),
slack: interviews.slack.as_ref().map(resolve_interview_provider),
discord: interviews.discord.as_ref().map(resolve_interview_provider),
teams: interviews.teams.as_ref().map(resolve_interview_provider),
}
}

View file

@ -1,12 +1,12 @@
use fabro_types::settings::InterpString;
use fabro_types::settings::server::{
DiscordIntegrationSettings, GithubIntegrationSettings, GithubIntegrationStrategy,
IntegrationWebhooksSettings, IpAllowEntry, ObjectStoreProvider, ObjectStoreSettings,
ServerApiSettings, ServerArtifactsSettings, ServerAuthGithubSettings, ServerAuthMethod,
ServerAuthSettings, ServerIntegrationsSettings, ServerIpAllowlistOverrideSettings,
ServerIpAllowlistSettings, ServerListenSettings, ServerLoggingSettings, ServerNamespace,
ServerSchedulerSettings, ServerSlateDbSettings, ServerStorageSettings, ServerWebSettings,
SlackIntegrationSettings, TeamsIntegrationSettings, WebhookStrategy,
GithubIntegrationSettings, GithubIntegrationStrategy, IntegrationWebhooksSettings,
IpAllowEntry, ObjectStoreProvider, ObjectStoreSettings, ServerApiSettings,
ServerArtifactsSettings, ServerAuthGithubSettings, ServerAuthMethod, ServerAuthSettings,
ServerIntegrationsSettings, ServerIpAllowlistOverrideSettings, ServerIpAllowlistSettings,
ServerListenSettings, ServerLoggingSettings, ServerNamespace, ServerSchedulerSettings,
ServerSlateDbSettings, ServerStorageSettings, ServerWebSettings, SlackIntegrationSettings,
WebhookStrategy,
};
use fabro_util::Home;
@ -454,7 +454,7 @@ fn resolve_integrations(
errors: &mut Vec<ResolveError>,
) -> ServerIntegrationsSettings {
ServerIntegrationsSettings {
github: layer
github: layer
.and_then(|integrations| integrations.github.as_ref())
.map(|github| GithubIntegrationSettings {
enabled: github.enabled.unwrap_or(true),
@ -467,25 +467,13 @@ fn resolve_integrations(
}),
})
.unwrap_or_default(),
slack: layer
slack: layer
.and_then(|integrations| integrations.slack.as_ref())
.map(|slack| SlackIntegrationSettings {
enabled: slack.enabled.unwrap_or(true),
default_channel: slack.default_channel.clone(),
})
.unwrap_or_default(),
discord: layer
.and_then(|integrations| integrations.discord.as_ref())
.map(|discord| DiscordIntegrationSettings {
enabled: discord.enabled.unwrap_or(true),
})
.unwrap_or_default(),
teams: layer
.and_then(|integrations| integrations.teams.as_ref())
.map(|teams| TeamsIntegrationSettings {
enabled: teams.enabled.unwrap_or(true),
})
.unwrap_or_default(),
}
}

View file

@ -26,6 +26,92 @@ fn resolves_run_defaults_from_empty_settings() {
assert!(settings.pull_request.is_none());
}
#[test]
fn resolved_run_chat_surfaces_are_slack_only() {
let settings = WorkflowSettingsBuilder::from_toml(
r##"
_version = 1
[run.notifications.ops]
enabled = true
provider = "slack"
events = ["run.completed"]
[run.notifications.ops.slack]
channel = "#ops"
[run.interviews]
provider = "slack"
[run.interviews.slack]
channel = "#ops"
"##,
)
.expect("slack-only chat settings should resolve")
.run;
let route = settings
.notifications
.get("ops")
.expect("notification route should resolve");
assert_eq!(
serde_json::to_value(route).expect("route should serialize"),
serde_json::json!({
"enabled": true,
"provider": "slack",
"events": ["run.completed"],
"slack": {
"channel": "#ops",
},
})
);
assert_eq!(
serde_json::to_value(&settings.interviews).expect("interviews should serialize"),
serde_json::json!({
"provider": "slack",
"slack": {
"channel": "#ops",
},
})
);
}
#[test]
fn parsing_rejects_unknown_run_chat_destinations() {
let notifications = r##"
_version = 1
[run.notifications.ops.chatapp]
channel = "#ops"
"##;
let err = notifications
.parse::<SettingsLayer>()
.expect_err("unknown notification destination should be rejected");
let message = err.to_string();
assert!(
message.contains("chatapp") || message.contains("unknown field"),
"expected notification parse error for unknown chat provider, got: {message}"
);
let interviews = r##"
_version = 1
[run.interviews.chatapp]
channel = "#ops"
"##;
let err = interviews
.parse::<SettingsLayer>()
.expect_err("unknown interview destination should be rejected");
let message = err.to_string();
assert!(
message.contains("chatapp") || message.contains("unknown field"),
"expected interview parse error for unknown chat provider, got: {message}"
);
}
#[test]
fn resolves_explicit_stop_on_terminal_false() {
let settings = WorkflowSettingsBuilder::from_toml(

View file

@ -109,6 +109,51 @@ fn resolves_server_defaults_from_empty_settings() {
assert!(!settings.slatedb.disk_cache);
}
#[test]
fn resolved_server_integrations_are_slack_only_for_chat() {
let settings = resolve_server(&empty_settings_with_auth_methods());
let integrations =
serde_json::to_value(&settings.integrations).expect("integrations should serialize");
assert_eq!(
integrations,
serde_json::json!({
"github": {
"enabled": false,
"strategy": "token",
"app_id": null,
"client_id": null,
"slug": null,
"webhooks": null,
},
"slack": {
"enabled": false,
"default_channel": null,
},
})
);
}
#[test]
fn parsing_rejects_unknown_server_integrations() {
let source = r#"
_version = 1
[server.integrations.chatapp]
enabled = true
"#;
let err = source
.parse::<SettingsLayer>()
.expect_err("unknown chat integration should be rejected");
let message = err.to_string();
assert!(
message.contains("chatapp") || message.contains("unknown field"),
"expected parse error for unknown chat provider, got: {message}"
);
}
#[test]
fn resolves_server_logging_destination_from_settings() {
let file = parse(

View file

@ -338,26 +338,6 @@ description = "Uncovered a DigitalOcean OAuth Refresh Token, which could allow p
regex = '''(?i)\b(dor_v1_[a-f0-9]{64})(?:['|\"|\n|\r|\s|\x60|;]|$)'''
keywords = ["dor_v1_"]
[[rules]]
id = "discord-api-token"
description = "Detected a Discord API key, potentially compromising communication channels and user data privacy on Discord."
regex = '''(?i)[\w.-]{0,50}?(?:discord)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-f0-9]{64})(?:['|\"|\n|\r|\s|\x60|;]|$)'''
keywords = ["discord"]
[[rules]]
id = "discord-client-id"
description = "Identified a Discord client ID, which may lead to unauthorized integrations and data exposure in Discord applications."
regex = '''(?i)[\w.-]{0,50}?(?:discord)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([0-9]{18})(?:['|\"|\n|\r|\s|\x60|;]|$)'''
entropy = 2
keywords = ["discord"]
[[rules]]
id = "discord-client-secret"
description = "Discovered a potential Discord client secret, risking compromised Discord bot integrations and data leaks."
regex = '''(?i)[\w.-]{0,50}?(?:discord)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9=_\-]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)'''
entropy = 2
keywords = ["discord"]
[[rules]]
id = "doppler-api-token"
description = "Discovered a Doppler API token, posing a risk to environment and secrets management security."
@ -2479,16 +2459,6 @@ keywords = [
"message_bird",
]
[[rules]]
id = "microsoft-teams-webhook"
description = "Uncovered a Microsoft Teams Webhook, which could lead to unauthorized access to team collaboration tools and data leaks."
regex = '''https://[a-z0-9]+\.webhook\.office\.com/webhookb2/[a-z0-9]{8}-([a-z0-9]{4}-){3}[a-z0-9]{12}@[a-z0-9]{8}-([a-z0-9]{4}-){3}[a-z0-9]{12}/IncomingWebhook/[a-z0-9]{32}/[a-z0-9]{8}-([a-z0-9]{4}-){3}[a-z0-9]{12}'''
keywords = [
"webhook.office.com",
"webhookb2",
"incomingwebhook",
]
[[rules]]
id = "netlify-access-token"
description = "Detected a Netlify Access Token, potentially compromising web hosting services and site management."
@ -3047,4 +3017,3 @@ id = "zendesk-secret-key"
description = "Detected a Zendesk Secret Key, risking unauthorized access to customer support services and sensitive ticketing data."
regex = '''(?i)[\w.-]{0,50}?(?:zendesk)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{40})(?:['|\"|\n|\r|\s|\x60|;]|$)'''
keywords = ["zendesk"]

View file

@ -45,12 +45,12 @@ pub use run::{
ScmGitHubSettings, TlsMode,
};
pub use server::{
DiscordIntegrationSettings, GithubIntegrationSettings, IntegrationWebhooksSettings,
IpAllowEntry, LogDestination, ObjectStoreSettings, ServerApiSettings, ServerArtifactsSettings,
ServerAuthGithubSettings, ServerAuthMethod, ServerAuthSettings, ServerIntegrationsSettings,
GithubIntegrationSettings, IntegrationWebhooksSettings, IpAllowEntry, LogDestination,
ObjectStoreSettings, ServerApiSettings, ServerArtifactsSettings, ServerAuthGithubSettings,
ServerAuthMethod, ServerAuthSettings, ServerIntegrationsSettings,
ServerIpAllowlistOverrideSettings, ServerIpAllowlistSettings, ServerListenSettings,
ServerLoggingSettings, ServerNamespace, ServerSchedulerSettings, ServerSlateDbSettings,
ServerStorageSettings, ServerWebSettings, SlackIntegrationSettings, TeamsIntegrationSettings,
ServerStorageSettings, ServerWebSettings, SlackIntegrationSettings,
};
pub use size::{ParseSizeError, Size};
pub use workflow::WorkflowNamespace;

View file

@ -302,8 +302,6 @@ pub struct NotificationRouteSettings {
pub provider: Option<String>,
pub events: Vec<String>,
pub slack: Option<NotificationProviderSettings>,
pub discord: Option<NotificationProviderSettings>,
pub teams: Option<NotificationProviderSettings>,
}
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
@ -315,8 +313,6 @@ pub struct NotificationProviderSettings {
pub struct RunInterviewsSettings {
pub provider: Option<String>,
pub slack: Option<InterviewProviderSettings>,
pub discord: Option<InterviewProviderSettings>,
pub teams: Option<InterviewProviderSettings>,
}
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]

View file

@ -258,10 +258,8 @@ pub struct ServerLoggingSettings {
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct ServerIntegrationsSettings {
pub github: GithubIntegrationSettings,
pub slack: SlackIntegrationSettings,
pub discord: DiscordIntegrationSettings,
pub teams: TeamsIntegrationSettings,
pub github: GithubIntegrationSettings,
pub slack: SlackIntegrationSettings,
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
@ -280,16 +278,6 @@ pub struct SlackIntegrationSettings {
pub default_channel: Option<InterpString>,
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct DiscordIntegrationSettings {
pub enabled: bool,
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct TeamsIntegrationSettings {
pub enabled: bool,
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct IntegrationWebhooksSettings {
pub strategy: Option<WebhookStrategy>,

View file

@ -77,7 +77,6 @@ models/diff-file.ts
models/diff-stats.ts
models/diff-summary.ts
models/dirty-status.ts
models/discord-integration-settings.ts
models/disk-usage-response.ts
models/disk-usage-run-row.ts
models/disk-usage-summary-row.ts
@ -327,7 +326,6 @@ models/system-info-response.ts
models/system-repair-run-issue.ts
models/system-repair-runs-response.ts
models/system-run-counts.ts
models/teams-integration-settings.ts
models/terminal-status.ts
models/timeline-entry-response.ts
models/tls-mode.ts

View file

@ -1,20 +0,0 @@
/* tslint:disable */
/* eslint-disable */
/**
* Fabro Run API
* HTTP API for managing Fabro workflow run executions.
*
* The version of the OpenAPI document: 0.1.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
export interface DiscordIntegrationSettings {
'enabled': boolean;
}

View file

@ -55,7 +55,6 @@ export * from './diff-file';
export * from './diff-stats';
export * from './diff-summary';
export * from './dirty-status';
export * from './discord-integration-settings';
export * from './disk-usage-response';
export * from './disk-usage-run-row';
export * from './disk-usage-summary-row';
@ -304,7 +303,6 @@ export * from './system-info-response';
export * from './system-repair-run-issue';
export * from './system-repair-runs-response';
export * from './system-run-counts';
export * from './teams-integration-settings';
export * from './terminal-status';
export * from './timeline-entry-response';
export * from './tls-mode';

View file

@ -22,7 +22,5 @@ export interface NotificationRouteSettings {
'provider': string | null;
'events': Array<string>;
'slack': NotificationProviderSettings | null;
'discord': NotificationProviderSettings | null;
'teams': NotificationProviderSettings | null;
}

View file

@ -20,7 +20,5 @@ import type { InterviewProviderSettings } from './interview-provider-settings';
export interface RunInterviewsSettings {
'provider': string | null;
'slack': InterviewProviderSettings | null;
'discord': InterviewProviderSettings | null;
'teams': InterviewProviderSettings | null;
}

View file

@ -13,23 +13,15 @@
*/
// May contain unused imports in some cases
// @ts-ignore
import type { DiscordIntegrationSettings } from './discord-integration-settings';
// May contain unused imports in some cases
// @ts-ignore
import type { GithubIntegrationSettings } from './github-integration-settings';
// May contain unused imports in some cases
// @ts-ignore
import type { SlackIntegrationSettings } from './slack-integration-settings';
// May contain unused imports in some cases
// @ts-ignore
import type { TeamsIntegrationSettings } from './teams-integration-settings';
export interface ServerIntegrationsSettings {
'github': GithubIntegrationSettings;
'slack': SlackIntegrationSettings;
'discord': DiscordIntegrationSettings;
'teams': TeamsIntegrationSettings;
}

View file

@ -1,20 +0,0 @@
/* tslint:disable */
/* eslint-disable */
/**
* Fabro Run API
* HTTP API for managing Fabro workflow run executions.
*
* The version of the OpenAPI document: 0.1.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
export interface TeamsIntegrationSettings {
'enabled': boolean;
}