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
12 changes: 6 additions & 6 deletions .github/workflows/update-awf-version.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ There are four items to check:
| Item | Upstream Source | Local Path |
|------|---------------|------------|
| `AWF_VERSION` | [github/gh-aw-firewall](https://github.com/github/gh-aw-firewall) latest release | `src/compile/common.rs` |
| `COPILOT_CLI_VERSION` | [github/copilot-cli](https://github.com/github/copilot-cli) latest release | `src/compile/common.rs` |
| `COPILOT_CLI_VERSION` | [github/copilot-cli](https://github.com/github/copilot-cli) latest release | `src/engine.rs` |
| `MCPG_VERSION` | [github/gh-aw-mcpg](https://github.com/github/gh-aw-mcpg) latest release | `src/compile/common.rs` |
| `ecosystem_domains.json` | [github/gh-aw](https://github.com/github/gh-aw) `pkg/workflow/data/ecosystem_domains.json` on `main` | `src/data/ecosystem_domains.json` |

Expand All @@ -45,11 +45,11 @@ Fetch the latest release of the upstream repository. Record the tag name, stripp

### Step 2: Read the Current Version

Read the file `src/compile/common.rs` in this repository and find the corresponding constant:
Read the corresponding file in this repository and find the constant:

- `pub const AWF_VERSION: &str = "...";`
- `pub const COPILOT_CLI_VERSION: &str = "...";`
- `pub const MCPG_VERSION: &str = "...";`
- `pub const AWF_VERSION: &str = "...";` in `src/compile/common.rs`
- `pub const COPILOT_CLI_VERSION: &str = "...";` in `src/engine.rs`
- `pub const MCPG_VERSION: &str = "...";` in `src/compile/common.rs`

Extract the version string.

Expand Down Expand Up @@ -89,7 +89,7 @@ If the latest version is newer than the current constant:
```markdown
## Dependency Update

Updates the pinned `COPILOT_CLI_VERSION` constant in `src/compile/common.rs` from `<old-version>` to `<latest-version>`.
Updates the pinned `COPILOT_CLI_VERSION` constant in `src/engine.rs` from `<old-version>` to `<latest-version>`.

### Release

Expand Down
73 changes: 60 additions & 13 deletions src/compile/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -459,14 +459,25 @@ pub fn validate_checkout_list(repositories: &[Repository], checkout: &[String])
Ok(())
}

/// Generate copilot CLI params from front matter configuration
pub fn generate_copilot_params(
/// Generate engine CLI args from front matter configuration.
///
/// Delegates to the Engine implementation (currently Copilot CLI).
pub fn generate_engine_args(
front_matter: &FrontMatter,
extensions: &[super::extensions::Extension],
) -> Result<String> {
crate::engine::GITHUB_COPILOT_CLI_ENGINE.generate_cli_params(front_matter, extensions)
}

/// Backwards-compatible alias for `generate_engine_args`.
#[allow(dead_code)]
pub fn generate_copilot_params(
front_matter: &FrontMatter,
extensions: &[super::extensions::Extension],
) -> Result<String> {
generate_engine_args(front_matter, extensions)
}

/// Compute the effective workspace based on explicit setting and checkout configuration.
pub fn compute_effective_workspace(
explicit_workspace: &Option<String>,
Expand Down Expand Up @@ -592,7 +603,10 @@ pub const AWF_VERSION: &str = "0.25.26";
/// Version of the GitHub Copilot CLI (Microsoft.Copilot.CLI.linux-x64) NuGet package to install.
/// Update this when upgrading to a new Copilot CLI release.
/// See: https://pkgs.dev.azure.com/msazuresphere/_packaging/Guardian1ESPTUpstreamOrgFeed/nuget/v3/index.json
pub const COPILOT_CLI_VERSION: &str = "1.0.34";
///
/// Re-exported from `crate::engine` for backwards compatibility.
#[allow(dead_code)]
pub const COPILOT_CLI_VERSION: &str = crate::engine::COPILOT_CLI_VERSION;

/// Prefix used to identify agentic pipeline YAML files generated by ado-aw.
pub const HEADER_MARKER: &str = "# @ado-aw";
Expand Down Expand Up @@ -730,7 +744,7 @@ pub fn generate_debug_pipeline_replacements(debug: bool) -> Vec<(String, String)
- bash: |
echo "=== Probing MCP backends ==="
PROBE_FAILED=false
for server in $(jq -r '.mcpServers | keys[]' /tmp/awf-tools/mcp-config.json); do
for server in $(jq -r '.mcpServers | keys[]' {{ engine_mcp_config_path }}); do
echo ""
echo "--- Probing: $server ---"
# MCP requires initialize handshake before tools/list.
Expand Down Expand Up @@ -910,13 +924,19 @@ pub fn generate_acquire_ado_token(service_connection: Option<&str>, variable_nam
}
}

/// Generate the env block entries for the copilot AWF step (Stage 1 agent).
/// Generate the env block entries for the engine AWF step (Stage 1 agent).
/// Uses the read-only token from the read service connection.
/// When not configured, omits ADO access tokens entirely.
pub fn generate_copilot_ado_env(read_service_connection: Option<&str>) -> String {
pub fn generate_engine_ado_env(read_service_connection: Option<&str>) -> String {
crate::engine::GITHUB_COPILOT_CLI_ENGINE.generate_agent_ado_env(read_service_connection)
}

/// Backwards-compatible alias for `generate_engine_ado_env`.
#[allow(dead_code)]
pub fn generate_copilot_ado_env(read_service_connection: Option<&str>) -> String {
generate_engine_ado_env(read_service_connection)
}

/// Generate the env block entries for the executor step (Stage 3 Execution).
/// Uses the write token from the write service connection.
/// When not configured, omits ADO access tokens entirely.
Expand Down Expand Up @@ -1966,8 +1986,9 @@ pub async fn compile_shared(
}
}

// 4. Generate copilot params
let copilot_params = generate_copilot_params(front_matter, extensions)?;
// 4. Generate engine args
let engine = &crate::engine::GITHUB_COPILOT_CLI_ENGINE;
let engine_args = generate_engine_args(front_matter, extensions)?;

// 5. Compute workspace, working directory, triggers
let effective_workspace = compute_effective_workspace(
Expand Down Expand Up @@ -2015,7 +2036,7 @@ pub async fn compile_shared(
.and_then(|p| p.read.as_deref()),
"SC_READ_TOKEN",
);
let copilot_ado_env = generate_copilot_ado_env(
let engine_ado_env = generate_engine_ado_env(
front_matter
.permissions
.as_ref()
Expand Down Expand Up @@ -2067,13 +2088,41 @@ pub async fn compile_shared(
template = replace_with_indent(&template, placeholder, replacement);
}

// 14. Shared replacements
// 14. Generate engine-specific template values
let compiler_version = env!("CARGO_PKG_VERSION");
let integrity_check = generate_integrity_check(config.skip_integrity);
let engine_install = engine.install_steps();
let engine_version = engine.version();
let engine_run = engine.invocation(
"/tmp/awf-tools/agent-prompt.md",
Some(engine.mcp_config_path()),
&engine_args,
);
let engine_run_detection = engine.invocation(
"/tmp/awf-tools/threat-analysis-prompt.md",
None,
&engine_args,
);
let engine_home_config_dir = engine.home_config_dir();
let engine_log_dir = engine.log_dir();
let engine_mcp_config_path = engine.mcp_config_path();
let replacements: Vec<(&str, &str)> = vec![
("{{ parameters }}", &parameters_yaml),
("{{ compiler_version }}", compiler_version),
("{{ copilot_version }}", COPILOT_CLI_VERSION),
// Engine-specific replacements (new markers)
("{{ engine_install }}", &engine_install),
("{{ engine_version }}", engine_version),
("{{ engine_args }}", &engine_args),
("{{ engine_run }}", &engine_run),
("{{ engine_run_detection }}", &engine_run_detection),
("{{ engine_ado_env }}", &engine_ado_env),
("{{ engine_home_config_dir }}", engine_home_config_dir),
("{{ engine_log_dir }}", engine_log_dir),
("{{ engine_mcp_config_path }}", engine_mcp_config_path),
// Legacy markers (kept for backwards compatibility during transition)
("{{ copilot_version }}", engine_version),
("{{ copilot_params }}", &engine_args),
("{{ copilot_ado_env }}", &engine_ado_env),
("{{ pool }}", &pool),
("{{ setup_job }}", &setup_job),
("{{ teardown_job }}", &teardown_job),
Expand All @@ -2091,7 +2140,6 @@ pub async fn compile_shared(
("{{ agent }}", &agent_name),
("{{ agent_name }}", &front_matter.name),
("{{ agent_description }}", &front_matter.description),
("{{ copilot_params }}", &copilot_params),
("{{ source_path }}", &source_path),
// integrity_check must come before pipeline_path because the
// integrity step content itself contains {{ pipeline_path }}.
Expand All @@ -2101,7 +2149,6 @@ pub async fn compile_shared(
("{{ workspace }}", &working_directory),
("{{ agent_content }}", markdown_body),
("{{ acquire_ado_token }}", &acquire_read_token),
("{{ copilot_ado_env }}", &copilot_ado_env),
("{{ acquire_write_token }}", &acquire_write_token),
("{{ executor_ado_env }}", &executor_ado_env),
];
Expand Down
3 changes: 3 additions & 0 deletions src/compile/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,13 @@ use std::path::{Path, PathBuf};

pub use common::parse_markdown;
pub use common::HEADER_MARKER;
pub use common::generate_engine_args;
#[allow(unused_imports)]
pub use common::generate_copilot_params;
pub use common::generate_mcpg_config;
pub use common::MCPG_IMAGE;
pub use common::MCPG_VERSION;
#[allow(unused_imports)]
pub use common::MCPG_PORT;
pub use types::{CompileTarget, FrontMatter};

Expand Down
85 changes: 20 additions & 65 deletions src/data/1es-base.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,30 +58,7 @@ extends:

{{ cancel_previous_builds }}

- task: NuGetAuthenticate@1
displayName: "Authenticate NuGet Feed"

- task: NuGetCommand@2
displayName: "Install Copilot CLI"
inputs:
command: 'custom'
arguments: 'install Microsoft.Copilot.CLI.linux-x64 -Source "https://pkgs.dev.azure.com/msazuresphere/_packaging/Guardian1ESPTUpstreamOrgFeed/nuget/v3/index.json" -Version {{ copilot_version }} -OutputDirectory $(Agent.TempDirectory)/tools -ExcludeVersion -NonInteractive'

- bash: |
ls -la "$(Agent.TempDirectory)/tools"
echo "##vso[task.prependpath]$(Agent.TempDirectory)/tools/Microsoft.Copilot.CLI.linux-x64"

# Copy copilot binary to /tmp so it's accessible inside AWF container
# (AWF auto-mounts /tmp:/tmp:rw but not Agent.TempDirectory)
mkdir -p /tmp/awf-tools
cp "$(Agent.TempDirectory)/tools/Microsoft.Copilot.CLI.linux-x64/copilot" /tmp/awf-tools/copilot
chmod +x /tmp/awf-tools/copilot
displayName: "Add copilot to PATH"

- bash: |
copilot --version
copilot -h
displayName: "Output copilot version"
{{ engine_install }}

- bash: |
COMPILER_VERSION="{{ compiler_version }}"
Expand Down Expand Up @@ -131,7 +108,7 @@ extends:
displayName: "Prepare MCPG config"

- bash: |
mkdir -p "$HOME/.copilot"
mkdir -p "{{ engine_home_config_dir }}"
mkdir -p /tmp/awf-tools/staging

echo "HOME: $HOME"
Expand Down Expand Up @@ -322,22 +299,22 @@ extends:
echo "Gateway output:"
cat "$GATEWAY_OUTPUT"

# Convert gateway output to Copilot CLI mcp-config.json.
# Convert gateway output to engine mcp-config.json.
# Mirrors gh-aw's convert_gateway_config_copilot.cjs:
# - Rewrite URLs from 127.0.0.1 to host.docker.internal (AWF container needs
# host.docker.internal to reach MCPG on the host; 127.0.0.1 is container loopback)
# - Ensure tools: ["*"] on each server entry (Copilot CLI requirement)
# - Preserve all other fields (headers, type, etc.)
jq --arg prefix "http://$(MCP_GATEWAY_DOMAIN):$(MCP_GATEWAY_PORT)" \
'.mcpServers |= (to_entries | sort_by(.key) | map(.value.url |= sub("^http://[^/]+/"; "\($prefix)/") | .value.tools = ["*"]) | from_entries)' \
"$GATEWAY_OUTPUT" > /tmp/awf-tools/mcp-config.json
"$GATEWAY_OUTPUT" > {{ engine_mcp_config_path }}

# Also write to $HOME/.copilot for host-side use
cp /tmp/awf-tools/mcp-config.json "$HOME/.copilot/mcp-config.json"
chmod 600 /tmp/awf-tools/mcp-config.json "$HOME/.copilot/mcp-config.json"
# Also write to engine home config dir for host-side use
cp {{ engine_mcp_config_path }} "{{ engine_home_config_dir }}/mcp-config.json"
chmod 600 {{ engine_mcp_config_path }} "{{ engine_home_config_dir }}/mcp-config.json"

echo "Generated MCP config at: /tmp/awf-tools/mcp-config.json"
cat /tmp/awf-tools/mcp-config.json
echo "Generated MCP config at: {{ engine_mcp_config_path }}"
cat {{ engine_mcp_config_path }}
displayName: "Start MCP Gateway (MCPG)"
{{ mcpg_step_env }}

Expand Down Expand Up @@ -370,7 +347,7 @@ extends:
--container-workdir "{{ working_directory }}" \
--log-level info \
--proxy-logs-dir "$(Agent.TempDirectory)/staging/logs/firewall" \
-- '/tmp/awf-tools/copilot --prompt "$(cat /tmp/awf-tools/agent-prompt.md)" --additional-mcp-config @/tmp/awf-tools/mcp-config.json {{ copilot_params }}' \
-- '{{ engine_run }}' \
2>&1 \
| sed -u 's/##vso\[/[VSO-FILTERED] vso[/g; s/##\[/[VSO-FILTERED] [/g' \
| tee "$AGENT_OUTPUT_FILE" \
Expand All @@ -383,10 +360,10 @@ extends:
fi

exit $AGENT_EXIT_CODE
displayName: "Run copilot (AWF network isolated)"
displayName: "Run agent (AWF network isolated)"
workingDirectory: {{ working_directory }}
env:
{{ copilot_ado_env }}
{{ engine_ado_env }}
GITHUB_TOKEN: $(GITHUB_TOKEN)
GITHUB_READ_ONLY: 1
COPILOT_OTEL_ENABLED: "true"
Expand Down Expand Up @@ -422,8 +399,8 @@ extends:
- bash: |
# Copy all logs to output directory for artifact upload
mkdir -p "$(Agent.TempDirectory)/staging/logs"
if [ -d ~/.copilot/logs ]; then
cp -r ~/.copilot/logs/* "$(Agent.TempDirectory)/staging/logs/" 2>/dev/null || true
if [ -d {{ engine_log_dir }} ]; then
cp -r {{ engine_log_dir }}/* "$(Agent.TempDirectory)/staging/logs/" 2>/dev/null || true
fi
if [ -d ~/.ado-aw/logs ]; then
cp -r ~/.ado-aw/logs/* "$(Agent.TempDirectory)/staging/logs/" 2>/dev/null || true
Expand Down Expand Up @@ -455,29 +432,7 @@ extends:
- download: current
artifact: agent_outputs_$(Build.BuildId)

- task: NuGetAuthenticate@1
displayName: "Authenticate NuGet Feed"

- task: NuGetCommand@2
displayName: "Install Copilot CLI"
inputs:
command: 'custom'
arguments: 'install Microsoft.Copilot.CLI.linux-x64 -Source "https://pkgs.dev.azure.com/msazuresphere/_packaging/Guardian1ESPTUpstreamOrgFeed/nuget/v3/index.json" -Version {{ copilot_version }} -OutputDirectory $(Agent.TempDirectory)/tools -ExcludeVersion -NonInteractive'

- bash: |
ls -la "$(Agent.TempDirectory)/tools"
echo "##vso[task.prependpath]$(Agent.TempDirectory)/tools/Microsoft.Copilot.CLI.linux-x64"

# Copy copilot binary to /tmp so it's accessible inside AWF container
mkdir -p /tmp/awf-tools
cp "$(Agent.TempDirectory)/tools/Microsoft.Copilot.CLI.linux-x64/copilot" /tmp/awf-tools/copilot
chmod +x /tmp/awf-tools/copilot
displayName: "Add copilot to PATH"

- bash: |
copilot --version
copilot -h
displayName: "Output copilot version"
{{ engine_install }}

- bash: |
COMPILER_VERSION="{{ compiler_version }}"
Expand Down Expand Up @@ -563,7 +518,7 @@ extends:
--container-workdir "{{ working_directory }}" \
--log-level info \
--proxy-logs-dir "$(Agent.TempDirectory)/threat-analysis-logs/firewall" \
-- '/tmp/awf-tools/copilot --prompt "$(cat /tmp/awf-tools/threat-analysis-prompt.md)" {{ copilot_params }}' \
-- '{{ engine_run_detection }}' \
2>&1 \
| sed -u 's/##vso\[/[VSO-FILTERED] vso[/g; s/##\[/[VSO-FILTERED] [/g' \
| tee "$THREAT_OUTPUT_FILE" \
Expand Down Expand Up @@ -641,9 +596,9 @@ extends:
- bash: |
# Copy all logs to analyzed outputs for artifact upload
mkdir -p "$(Agent.TempDirectory)/analyzed_outputs/logs"
if [ -d ~/.copilot/logs ]; then
if [ -d {{ engine_log_dir }} ]; then
mkdir -p "$(Agent.TempDirectory)/analyzed_outputs/logs/copilot"
cp -r ~/.copilot/logs/* "$(Agent.TempDirectory)/analyzed_outputs/logs/copilot/" 2>/dev/null || true
cp -r {{ engine_log_dir }}/* "$(Agent.TempDirectory)/analyzed_outputs/logs/copilot/" 2>/dev/null || true
fi
if [ -d ~/.ado-aw/logs ]; then
mkdir -p "$(Agent.TempDirectory)/analyzed_outputs/logs/ado-aw"
Expand Down Expand Up @@ -723,9 +678,9 @@ extends:
# Copy agent output log from analyzed_outputs for optimisation use
cp "$(Pipeline.Workspace)/analyzed_outputs_$(Build.BuildId)/logs/agent-output.txt" \
"$(Agent.TempDirectory)/staging/logs/agent-output.txt" 2>/dev/null || true
if [ -d ~/.copilot/logs ]; then
if [ -d {{ engine_log_dir }} ]; then
mkdir -p "$(Agent.TempDirectory)/staging/logs/copilot"
cp -r ~/.copilot/logs/* "$(Agent.TempDirectory)/staging/logs/copilot/" 2>/dev/null || true
cp -r {{ engine_log_dir }}/* "$(Agent.TempDirectory)/staging/logs/copilot/" 2>/dev/null || true
fi
if [ -d ~/.ado-aw/logs ]; then
mkdir -p "$(Agent.TempDirectory)/staging/logs/ado-aw"
Expand Down
Loading