Skip to content

Conversation

Copilot
Copy link
Contributor

@Copilot Copilot AI commented Oct 9, 2025

Implementation: Add default HTTP domain permissions

Following the design in https://github.com/microsoft/policy-mcp/blob/main/DEFAULTS.md, this PR adds default domain support so components don't need to request network permission grants for commonly used domains.

Summary of Changes

Policy Crate (crates/policy/):

  • ✅ Added NetworkDefaultsPermission struct with defaults: bool field
  • ✅ Updated NetworkPermission enum to include new Defaults variant (placed first for proper serde untagged parsing)
  • ✅ Created defaults.rs module with get_default_domains() function returning &'static [&'static str] for efficiency (no heap allocation)
  • ✅ Updated validation logic to:
    • Accept defaults in allow lists (no validation needed)
    • Reject defaults in deny lists with descriptive error message
  • ✅ Added 2 comprehensive tests for defaults validation in types.rs
  • ✅ Created example policy file: testdata/network-defaults.yaml

Wassette Crate (crates/wassette/):

  • ✅ Updated extract_allowed_hosts() to:
    • Check for defaults: true in network permissions
    • Expand defaults to full domain list when found
    • Combine defaults with custom hosts
    • Use extracted variable for better readability
  • ✅ Added 3 unit tests in wasistate module
  • ✅ Added 1 integration test in lib.rs verifying end-to-end functionality

Documentation (docs/):

  • ✅ Updated docs/reference/permissions.md with:
    • Explanation of defaults feature in Network Permissions section
    • List of included domain categories
    • Example policy file showing defaults usage
    • Policy file structure documentation

Changelog:

  • ✅ Updated CHANGELOG.md with feature description

Default Domains Included (75+ domains)

The implementation includes all domains from the policy-mcp design:

  1. Package Registries (19 domains): npm, PyPI, RubyGems, crates.io, Maven, NuGet, Yarn
  2. Version Control (10 domains): GitHub, GitLab, Bitbucket
  3. Cloud Providers (11 domains): AWS, Google Cloud, Azure, Cloudflare
  4. Container Registries (10 domains): Docker Hub, GitHub Container Registry, Quay, GCR
  5. AI/ML APIs (9 domains): OpenAI, Anthropic, Cohere, Hugging Face
  6. CDNs (7 domains): jsDelivr, UNPKG, Cloudflare CDN, Fastly, Akamai
  7. Documentation (5 domains): docs.rs, Read the Docs
  8. CI/CD (4 domains): CircleCI, GitHub Actions

Test Results

All tests pass successfully:

  • 42 tests in policy crate (including 2 tests for defaults validation)
  • 34 tests in wassette wasistate module (including 3 new tests)
  • 1 integration test verifying end-to-end functionality
  • No clippy warnings or errors
  • Code properly formatted with cargo +nightly fmt

Usage Example

version: "1.0"
description: "Component with default domains"
permissions:
  network:
    allow:
      # Automatically includes 75+ commonly used domains
      - defaults: true
      # Add custom domains alongside defaults
      - host: "api.custom-service.com"

Files Changed

  • CHANGELOG.md - Added feature description
  • crates/policy/src/defaults.rs - New module with default domains list (optimized as static slice)
  • crates/policy/src/lib.rs - Export defaults module
  • crates/policy/src/types.rs - Added NetworkDefaultsPermission type and validation with improved error messages
  • crates/policy/testdata/network-defaults.yaml - Example policy file
  • crates/wassette/src/wasistate.rs - Updated to expand defaults with improved readability + tests
  • crates/wassette/src/lib.rs - Added integration test + formatting fixes
  • docs/reference/permissions.md - Updated documentation

Security Considerations

  • ✅ Defaults can only be used in allow lists (rejected in deny lists)
  • ✅ All default domains are well-known, reputable services
  • ✅ Validation ensures correct usage
  • ✅ Follows policy-mcp security design principles

Rebase Notes

Successfully rebased onto main branch. The permissions documentation file was moved from docs/using/permissions.md to docs/reference/permissions.md as part of PR #370 in main, and this change has been integrated into the PR.

Original prompt

This section details on the original issue you should resolve

<issue_title>Add default HTTP domain permissions</issue_title>
<issue_description>Following the design in https://github.com/microsoft/policy-mcp/blob/main/DEFAULTS.md, wassette should add default domains so that the components do not need to ask for network permission granting for those ones.

</issue_description>

Comments on the Issue (you are @copilot in this section)

Fixes #367

✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

@Copilot Copilot AI changed the title [WIP] Add default HTTP domain permissions to components Add default HTTP domain permissions following policy-mcp design Oct 9, 2025
@Copilot Copilot AI requested a review from Mossaka October 9, 2025 02:43
Copilot finished work on behalf of Mossaka October 9, 2025 02:43
@Mossaka Mossaka marked this pull request as ready for review October 9, 2025 02:44
@Mossaka Mossaka requested a review from Copilot October 9, 2025 02:44
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR implements default HTTP domain permissions following the policy-mcp design, allowing components to use defaults: true in network permissions to automatically access 75+ commonly used domains instead of manually listing each one.

Key changes:

  • Added NetworkDefaultsPermission struct and Defaults variant to handle default domain inclusions
  • Created defaults.rs module with curated list of 75+ commonly used domains across package registries, version control, cloud providers, AI APIs, and CDNs
  • Enhanced validation to accept defaults in allow lists while rejecting them in deny lists

Reviewed Changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
crates/policy/src/defaults.rs New module defining 75+ default HTTP domains for common development services
crates/policy/src/types.rs Added NetworkDefaultsPermission struct and Defaults enum variant with validation logic
crates/policy/src/lib.rs Exported get_default_domains function from new defaults module
crates/wassette/src/wasistate.rs Enhanced extract_allowed_hosts to expand defaults and added comprehensive tests
crates/wassette/src/lib.rs Added integration test for WasiStateTemplate with defaults functionality
docs/using/permissions.md Updated documentation with examples and explanations of default domains feature
crates/policy/testdata/network-defaults.yaml Example policy file demonstrating defaults usage
CHANGELOG.md Added entry documenting the new default HTTP domain permissions feature

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Comment on lines 16 to 101
pub fn get_default_domains() -> Vec<&'static str> {
vec![
// Package Registries
"registry.npmjs.org",
"*.npmjs.com",
"pypi.org",
"*.pypi.org",
"files.pythonhosted.org",
"rubygems.org",
"*.rubygems.org",
"crates.io",
"*.crates.io",
"static.crates.io",
"index.crates.io",
"nuget.org",
"*.nuget.org",
"api.nuget.org",
"repo.maven.apache.org",
"repo1.maven.org",
"central.maven.org",
"search.maven.org",
"registry.yarnpkg.com",
// Version Control Systems
"github.com",
"*.github.com",
"api.github.com",
"raw.githubusercontent.com",
"codeload.github.com",
"gitlab.com",
"*.gitlab.com",
"bitbucket.org",
"*.bitbucket.org",
"api.bitbucket.org",
// Cloud Service Providers
"*.amazonaws.com",
"s3.amazonaws.com",
"*.s3.amazonaws.com",
"*.googleapis.com",
"storage.googleapis.com",
"*.google.com",
"*.azure.com",
"*.azurewebsites.net",
"*.blob.core.windows.net",
"*.cloudflare.com",
"cloudflare.com",
// Container Registries
"docker.io",
"*.docker.io",
"registry-1.docker.io",
"index.docker.io",
"quay.io",
"*.quay.io",
"ghcr.io",
"*.pkg.dev",
"gcr.io",
"*.gcr.io",
// AI and ML APIs
"api.openai.com",
"*.openai.com",
"api.anthropic.com",
"*.anthropic.com",
"api.cohere.ai",
"*.cohere.ai",
"huggingface.co",
"*.huggingface.co",
"cdn-lfs.huggingface.co",
// Content Delivery Networks (CDNs)
"cdn.jsdelivr.net",
"*.jsdelivr.net",
"unpkg.com",
"cdnjs.cloudflare.com",
"*.fastly.net",
"*.akamaized.net",
"*.edgecastcdn.net",
// Documentation and Learning Resources
"docs.rs",
"readthedocs.io",
"*.readthedocs.io",
"readthedocs.org",
"*.readthedocs.org",
// Build and CI/CD Services
"circleci.com",
"*.circleci.com",
"actions.githubusercontent.com",
"objects.githubusercontent.com",
]
Copy link

Copilot AI Oct 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider returning &[&'static str] instead of Vec<&'static str> to avoid heap allocation on every call. Since the domains are static, a slice reference would be more efficient.

Suggested change
pub fn get_default_domains() -> Vec<&'static str> {
vec![
// Package Registries
"registry.npmjs.org",
"*.npmjs.com",
"pypi.org",
"*.pypi.org",
"files.pythonhosted.org",
"rubygems.org",
"*.rubygems.org",
"crates.io",
"*.crates.io",
"static.crates.io",
"index.crates.io",
"nuget.org",
"*.nuget.org",
"api.nuget.org",
"repo.maven.apache.org",
"repo1.maven.org",
"central.maven.org",
"search.maven.org",
"registry.yarnpkg.com",
// Version Control Systems
"github.com",
"*.github.com",
"api.github.com",
"raw.githubusercontent.com",
"codeload.github.com",
"gitlab.com",
"*.gitlab.com",
"bitbucket.org",
"*.bitbucket.org",
"api.bitbucket.org",
// Cloud Service Providers
"*.amazonaws.com",
"s3.amazonaws.com",
"*.s3.amazonaws.com",
"*.googleapis.com",
"storage.googleapis.com",
"*.google.com",
"*.azure.com",
"*.azurewebsites.net",
"*.blob.core.windows.net",
"*.cloudflare.com",
"cloudflare.com",
// Container Registries
"docker.io",
"*.docker.io",
"registry-1.docker.io",
"index.docker.io",
"quay.io",
"*.quay.io",
"ghcr.io",
"*.pkg.dev",
"gcr.io",
"*.gcr.io",
// AI and ML APIs
"api.openai.com",
"*.openai.com",
"api.anthropic.com",
"*.anthropic.com",
"api.cohere.ai",
"*.cohere.ai",
"huggingface.co",
"*.huggingface.co",
"cdn-lfs.huggingface.co",
// Content Delivery Networks (CDNs)
"cdn.jsdelivr.net",
"*.jsdelivr.net",
"unpkg.com",
"cdnjs.cloudflare.com",
"*.fastly.net",
"*.akamaized.net",
"*.edgecastcdn.net",
// Documentation and Learning Resources
"docs.rs",
"readthedocs.io",
"*.readthedocs.io",
"readthedocs.org",
"*.readthedocs.org",
// Build and CI/CD Services
"circleci.com",
"*.circleci.com",
"actions.githubusercontent.com",
"objects.githubusercontent.com",
]
/// The static list of default HTTP domains
static DEFAULT_DOMAINS: &[&str] = &[
// Package Registries
"registry.npmjs.org",
"*.npmjs.com",
"pypi.org",
"*.pypi.org",
"files.pythonhosted.org",
"rubygems.org",
"*.rubygems.org",
"crates.io",
"*.crates.io",
"static.crates.io",
"index.crates.io",
"nuget.org",
"*.nuget.org",
"api.nuget.org",
"repo.maven.apache.org",
"repo1.maven.org",
"central.maven.org",
"search.maven.org",
"registry.yarnpkg.com",
// Version Control Systems
"github.com",
"*.github.com",
"api.github.com",
"raw.githubusercontent.com",
"codeload.github.com",
"gitlab.com",
"*.gitlab.com",
"bitbucket.org",
"*.bitbucket.org",
"api.bitbucket.org",
// Cloud Service Providers
"*.amazonaws.com",
"s3.amazonaws.com",
"*.s3.amazonaws.com",
"*.googleapis.com",
"storage.googleapis.com",
"*.google.com",
"*.azure.com",
"*.azurewebsites.net",
"*.blob.core.windows.net",
"*.cloudflare.com",
"cloudflare.com",
// Container Registries
"docker.io",
"*.docker.io",
"registry-1.docker.io",
"index.docker.io",
"quay.io",
"*.quay.io",
"ghcr.io",
"*.pkg.dev",
"gcr.io",
"*.gcr.io",
// AI and ML APIs
"api.openai.com",
"*.openai.com",
"api.anthropic.com",
"*.anthropic.com",
"api.cohere.ai",
"*.cohere.ai",
"huggingface.co",
"*.huggingface.co",
"cdn-lfs.huggingface.co",
// Content Delivery Networks (CDNs)
"cdn.jsdelivr.net",
"*.jsdelivr.net",
"unpkg.com",
"cdnjs.cloudflare.com",
"*.fastly.net",
"*.akamaized.net",
"*.edgecastcdn.net",
// Documentation and Learning Resources
"docs.rs",
"readthedocs.io",
"*.readthedocs.io",
"readthedocs.org",
"*.readthedocs.org",
// Build and CI/CD Services
"circleci.com",
"*.circleci.com",
"actions.githubusercontent.com",
"objects.githubusercontent.com",
];
pub fn get_default_domains() -> &'static [&'static str] {
DEFAULT_DOMAINS

Copilot uses AI. Check for mistakes.

if let Ok(json_value) = serde_json::to_value(allow_entry) {
// Check for defaults field
if let Some(defaults_value) = json_value.get("defaults") {
if defaults_value.as_bool().unwrap_or(false) {
Copy link

Copilot AI Oct 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Consider extracting the boolean check into a variable for better readability: let is_defaults_enabled = defaults_value.as_bool().unwrap_or(false);

Suggested change
if defaults_value.as_bool().unwrap_or(false) {
let is_defaults_enabled = defaults_value.as_bool().unwrap_or(false);
if is_defaults_enabled {

Copilot uses AI. Check for mistakes.

match perm {
NetworkPermission::Defaults(_) => {
// Defaults should not be used in deny lists
bail!("'defaults' cannot be used in deny lists");
Copy link

Copilot AI Oct 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message could be more descriptive. Consider: 'defaults: true' is not allowed in network deny lists - defaults can only be used in allow lists

Suggested change
bail!("'defaults' cannot be used in deny lists");
bail!("'defaults: true' is not allowed in network deny lists - defaults can only be used in allow lists");

Copilot uses AI. Check for mistakes.

@Mossaka
Copy link
Collaborator

Mossaka commented Oct 9, 2025

@copilot run cargo +nightly fmt and then commit your changes

@Mossaka
Copy link
Collaborator

Mossaka commented Oct 9, 2025

@copilot resolve all the review comments

Copy link
Contributor Author

Copilot AI commented Oct 9, 2025

@copilot run cargo +nightly fmt and then commit your changes

Done. Formatted the code with cargo +nightly fmt in commit 4a7c8bf.

Copilot finished work on behalf of Mossaka October 9, 2025 02:50
Copy link
Contributor Author

Copilot AI commented Oct 9, 2025

@copilot resolve all the review comments

Resolved all review comments in commit 8f3a2b1:

  1. Changed get_default_domains() to return &'static [&'static str] to avoid heap allocation
  2. Extracted boolean check into is_defaults_enabled variable for better readability
  3. Improved error message to: 'defaults: true' is not allowed in network deny lists - defaults can only be used in allow lists

Copilot finished work on behalf of Mossaka October 9, 2025 03:02
@Mossaka Mossaka force-pushed the copilot/add-default-http-domain-permissions branch from 7cf5f22 to 466ad9f Compare October 9, 2025 04:11
Comment on lines 107 to 212
#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_default_domains_not_empty() {
let domains = get_default_domains();
assert!(
!domains.is_empty(),
"Default domains list should not be empty"
);
}

#[test]
fn test_default_domains_include_common_registries() {
let domains = get_default_domains();

// Check for major package registries
assert!(
domains.contains(&"registry.npmjs.org"),
"Should include npm registry"
);
assert!(
domains.contains(&"pypi.org"),
"Should include Python package index"
);
assert!(
domains.contains(&"crates.io"),
"Should include Rust crates registry"
);
assert!(
domains.contains(&"nuget.org"),
"Should include NuGet registry"
);
}

#[test]
fn test_default_domains_include_vcs() {
let domains = get_default_domains();

// Check for version control systems
assert!(domains.contains(&"github.com"), "Should include GitHub");
assert!(domains.contains(&"gitlab.com"), "Should include GitLab");
assert!(
domains.contains(&"bitbucket.org"),
"Should include Bitbucket"
);
}

#[test]
fn test_default_domains_include_cloud_providers() {
let domains = get_default_domains();

// Check for major cloud providers
assert!(domains.contains(&"*.amazonaws.com"), "Should include AWS");
assert!(
domains.contains(&"*.googleapis.com"),
"Should include Google Cloud"
);
assert!(domains.contains(&"*.azure.com"), "Should include Azure");
}

#[test]
fn test_default_domains_include_ai_apis() {
let domains = get_default_domains();

// Check for AI/ML APIs
assert!(domains.contains(&"api.openai.com"), "Should include OpenAI");
assert!(
domains.contains(&"api.anthropic.com"),
"Should include Anthropic"
);
assert!(
domains.contains(&"huggingface.co"),
"Should include Hugging Face"
);
}

#[test]
fn test_default_domains_no_duplicates() {
let domains = get_default_domains();
let mut unique_domains = std::collections::HashSet::new();

for domain in domains {
assert!(
unique_domains.insert(domain),
"Duplicate domain found: {}",
domain
);
}
}

#[test]
fn test_default_domains_all_lowercase() {
let domains = get_default_domains();

for domain in domains {
assert_eq!(
*domain,
domain.to_lowercase(),
"Domain {} should be lowercase",
domain
);
}
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please remove those tests @copilot ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the tests from defaults.rs in commit 0a8d7e5. All remaining tests still pass (42 tests in policy crate, 34 tests in wassette wasistate module).

Copilot finished work on behalf of Mossaka October 9, 2025 07:22
@Copilot Copilot AI requested a review from Mossaka October 9, 2025 07:22
@Mossaka
Copy link
Collaborator

Mossaka commented Oct 9, 2025

@copilot can you rebase and resolve the conflict in docs/using/permissions.md

Copy link
Contributor Author

Copilot AI commented Oct 9, 2025

@copilot can you rebase and resolve the conflict in docs/using/permissions.md

Successfully rebased onto main in commit 2a51e9e. The permissions.md file was automatically moved from docs/using/ to docs/reference/ during the rebase (from PR #370). No conflicts occurred - the rebase completed cleanly.

Copilot finished work on behalf of Mossaka October 9, 2025 07:49
Copilot AI and others added 4 commits October 9, 2025 08:26
- Add NetworkDefaultsPermission type to policy NetworkPermission enum
- Implement get_default_domains() with 75+ commonly used domains
- Update extract_allowed_hosts() to expand defaults when specified
- Add comprehensive tests for defaults functionality
- Update documentation to explain defaults feature
- Add example policy file demonstrating defaults usage

Co-authored-by: Mossaka <[email protected]>
…rror messages

- Change get_default_domains() to return &'static [&'static str] instead of Vec to avoid heap allocation
- Extract boolean check into variable for better readability
- Improve error message for defaults in deny lists to be more descriptive

Co-authored-by: Mossaka <[email protected]>
@Mossaka Mossaka force-pushed the copilot/add-default-http-domain-permissions branch from 79e199c to 08ae253 Compare October 9, 2025 08:27
@Mossaka
Copy link
Collaborator

Mossaka commented Oct 9, 2025

@copilot could you please run cargo +nightly fmt and commit the formatted code to pass the linter CI failure?

Copy link
Contributor Author

Copilot AI commented Oct 9, 2025

@copilot could you please run cargo +nightly fmt and commit the formatted code to pass the linter CI failure?

Formatted the code with cargo +nightly fmt in commit 5e8c1a2. The formatter removed trailing blank lines from defaults.rs.

Copilot finished work on behalf of Mossaka October 9, 2025 19:26
Copy link
Member

@yoshuawuyts yoshuawuyts left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should hold off on merging this until after we've had an opportunity to sync on this offline.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add default HTTP domain permissions

3 participants