Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions codex-rs/app-server-protocol/schema/typescript/v2/index.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 21 additions & 0 deletions codex-rs/app-server-protocol/src/protocol/v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -950,13 +950,33 @@ pub struct ConfigRequirements {
pub allowed_sandbox_modes: Option<Vec<SandboxMode>>,
pub allowed_web_search_modes: Option<Vec<WebSearchMode>>,
pub feature_requirements: Option<BTreeMap<String, bool>>,
#[experimental("configRequirements/read.strictKnownMarketplaces")]
pub strict_known_marketplaces: Option<Vec<StrictKnownMarketplaceRequirement>>,
#[experimental("configRequirements/read.hooks")]
pub hooks: Option<ManagedHooksRequirements>,
pub enforce_residency: Option<ResidencyRequirement>,
#[experimental("configRequirements/read.network")]
pub network: Option<NetworkRequirements>,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct StrictKnownMarketplaceRequirement {
pub source_type: MarketplaceSourceType,
pub source: String,
pub ref_name: Option<String>,
pub sparse_paths: Option<Vec<String>>,
}

#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "snake_case")]
#[ts(export_to = "v2/")]
pub enum MarketplaceSourceType {
Git,
Local,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
Expand Down Expand Up @@ -9217,6 +9237,7 @@ mod tests {
allowed_sandbox_modes: None,
allowed_web_search_modes: None,
feature_requirements: None,
strict_known_marketplaces: None,
hooks: None,
enforce_residency: None,
network: None,
Expand Down
2 changes: 1 addition & 1 deletion codex-rs/app-server/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ Example with notification opt-out:
- `externalAgentConfig/import` — apply selected external-agent migration items by passing explicit `migrationItems` with `cwd` (`null` for home) and any plugin `details` returned by detect. When a request includes plugin imports, the server emits `externalAgentConfig/import/completed` after the full import finishes (immediately after the response when everything completed synchronously, or after background remote imports finish).
- `config/value/write` — write a single config key/value to the user's config.toml on disk.
- `config/batchWrite` — apply multiple config edits atomically to the user's config.toml on disk, with optional `reloadUserConfig: true` to hot-reload loaded threads.
- `configRequirements/read` — fetch loaded requirements constraints from `requirements.toml` and/or MDM (or `null` if none are configured), including allow-lists (`allowedApprovalPolicies`, `allowedSandboxModes`, `allowedWebSearchModes`), pinned feature values (`featureRequirements`), managed lifecycle hooks (`hooks`), `enforceResidency`, and `network` constraints such as canonical domain/socket permissions plus `managedAllowedDomainsOnly` and `dangerFullAccessDenylistOnly`.
- `configRequirements/read` — fetch loaded requirements constraints from `requirements.toml` and/or MDM (or `null` if none are configured), including allow-lists (`allowedApprovalPolicies`, `allowedSandboxModes`, `allowedWebSearchModes`), pinned feature values (`featureRequirements`), user-configured marketplace source restrictions (`strictKnownMarketplaces`), managed lifecycle hooks (`hooks`), `enforceResidency`, and `network` constraints such as canonical domain/socket permissions plus `managedAllowedDomainsOnly` and `dangerFullAccessDenylistOnly`.

### Example: Start or resume a thread

Expand Down
13 changes: 13 additions & 0 deletions codex-rs/app-server/src/codex_message_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6900,8 +6900,21 @@ impl CodexMessageProcessor {
}

async fn marketplace_add(&self, request_id: ConnectionRequestId, params: MarketplaceAddParams) {
let config = match self.load_latest_config(/*fallback_cwd*/ None).await {
Ok(config) => config,
Err(err) => {
self.outgoing.send_error(request_id, err).await;
return;
}
};
let result = add_marketplace_to_codex_home(
self.config.codex_home.to_path_buf(),
config
.config_layer_stack
.requirements()
.strict_known_marketplaces
.as_ref()
.map(|requirements| requirements.value.clone()),
MarketplaceAddRequest {
source: params.source,
ref_name: params.ref_name,
Expand Down
3 changes: 2 additions & 1 deletion codex-rs/app-server/src/codex_message_processor/plugins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ impl CodexMessageProcessor {
};

let result = plugins_manager
.install_plugin(request)
.install_plugin(&config, request)
.await
.map_err(Self::plugin_install_error)?;
let config = match self.load_latest_config(config_cwd).await {
Expand Down Expand Up @@ -610,6 +610,7 @@ impl CodexMessageProcessor {
| MarketplaceError::InvalidMarketplaceFile { .. }
| MarketplaceError::PluginNotFound { .. }
| MarketplaceError::PluginNotAvailable { .. }
| MarketplaceError::BlockedByRequirements { .. }
| MarketplaceError::PluginsDisabled
| MarketplaceError::InvalidPlugin(_) => invalid_request(err.to_string()),
MarketplaceError::Io { .. } => internal_error(format!("failed to {action}: {err}")),
Expand Down
33 changes: 28 additions & 5 deletions codex-rs/app-server/src/config/external_agent_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,22 @@ impl ExternalAgentConfigService {
ref_name: import_source.ref_name,
sparse_paths: Vec::new(),
};
let add_marketplace_outcome = add_marketplace(self.codex_home.clone(), request).await;
let config = ConfigBuilder::default()
.codex_home(self.codex_home.clone())
.fallback_cwd(Some(self.codex_home.clone()))
.build()
.await?;
let add_marketplace_outcome = add_marketplace(
self.codex_home.clone(),
config
.config_layer_stack
.requirements()
.strict_known_marketplaces
.as_ref()
.map(|requirements| requirements.value.clone()),
request,
)
.await;
let marketplace_path = match add_marketplace_outcome {
Ok(add_marketplace_outcome) => {
let Some(marketplace_path) = find_marketplace_manifest_path(
Expand All @@ -479,12 +494,20 @@ impl ExternalAgentConfigService {
continue;
}
};
let config = ConfigBuilder::default()
.codex_home(self.codex_home.clone())
.fallback_cwd(Some(self.codex_home.clone()))
.build()
.await?;
for plugin_name in plugin_names {
match plugins_manager
.install_plugin(PluginInstallRequest {
plugin_name: plugin_name.clone(),
marketplace_path: marketplace_path.clone(),
})
.install_plugin(
&config,
PluginInstallRequest {
plugin_name: plugin_name.clone(),
marketplace_path: marketplace_path.clone(),
},
)
.await
{
Ok(_) => outcome
Expand Down
Loading
Loading