Skip to content
Merged
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
15 changes: 15 additions & 0 deletions .github/workflows/nightly-deploy-pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ jobs:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: ${{ inputs.ref }}
persist-credentials: false
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: '22'
Expand All @@ -105,6 +106,7 @@ jobs:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: ${{ inputs.ref }}
persist-credentials: false
- uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
with:
version: '0.7.12'
Expand All @@ -126,6 +128,7 @@ jobs:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: ${{ inputs.ref }}
persist-credentials: false
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: '22'
Expand Down Expand Up @@ -176,6 +179,7 @@ jobs:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: ${{ inputs.ref }}
persist-credentials: false
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: '22'
Expand Down Expand Up @@ -212,6 +216,7 @@ jobs:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: ${{ inputs.ref }}
persist-credentials: false
- uses: ./.github/actions/configure-aws-credentials
with:
aws-region: ${{ vars.AWS_REGION || 'us-west-2' }}
Expand Down Expand Up @@ -243,6 +248,7 @@ jobs:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: ${{ inputs.ref }}
persist-credentials: false
- uses: ./.github/actions/configure-aws-credentials
with:
aws-region: ${{ vars.AWS_REGION || 'us-west-2' }}
Expand Down Expand Up @@ -281,6 +287,7 @@ jobs:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: ${{ inputs.ref }}
persist-credentials: false
- uses: ./.github/actions/configure-aws-credentials
with:
aws-region: ${{ vars.AWS_REGION || 'us-west-2' }}
Expand Down Expand Up @@ -317,6 +324,7 @@ jobs:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: ${{ inputs.ref }}
persist-credentials: false
- uses: ./.github/actions/configure-aws-credentials
with:
aws-region: ${{ vars.AWS_REGION || 'us-west-2' }}
Expand Down Expand Up @@ -348,6 +356,7 @@ jobs:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: ${{ inputs.ref }}
persist-credentials: false
- uses: ./.github/actions/configure-aws-credentials
with:
aws-region: ${{ vars.AWS_REGION || 'us-west-2' }}
Expand Down Expand Up @@ -379,6 +388,7 @@ jobs:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: ${{ inputs.ref }}
persist-credentials: false
- uses: ./.github/actions/configure-aws-credentials
with:
aws-region: ${{ vars.AWS_REGION || 'us-west-2' }}
Expand Down Expand Up @@ -410,6 +420,7 @@ jobs:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: ${{ inputs.ref }}
persist-credentials: false
- uses: ./.github/actions/configure-aws-credentials
with:
aws-region: ${{ vars.AWS_REGION || 'us-west-2' }}
Expand Down Expand Up @@ -440,6 +451,7 @@ jobs:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: ${{ inputs.ref }}
persist-credentials: false
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: '22'
Expand Down Expand Up @@ -475,6 +487,7 @@ jobs:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: ${{ inputs.ref }}
persist-credentials: false
- uses: ./.github/actions/configure-aws-credentials
with:
aws-region: ${{ vars.AWS_REGION || 'us-west-2' }}
Expand Down Expand Up @@ -509,6 +522,7 @@ jobs:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: ${{ inputs.ref }}
persist-credentials: false
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: '22'
Expand Down Expand Up @@ -573,6 +587,7 @@ jobs:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: ${{ inputs.ref }}
persist-credentials: false
- uses: ./.github/actions/configure-aws-credentials
with:
aws-region: ${{ vars.AWS_REGION || 'us-west-2' }}
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ jobs:

- name: Install frontend dependencies
if: steps.cache-frontend.outputs.cache-hit != 'true'
run: bash scripts/stack-frontend/install.sh
run: bash scripts/frontend/install.sh

- name: Save frontend node_modules cache
if: steps.cache-frontend.outputs.cache-hit != 'true'
Expand Down Expand Up @@ -307,7 +307,7 @@ jobs:

- name: Run backend tests with coverage
id: run-tests
run: bash scripts/stack-app-api/test.sh
run: bash scripts/backend/test.sh

- name: Upload backend coverage artifacts
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
Expand Down Expand Up @@ -348,7 +348,7 @@ jobs:

- name: Run frontend tests with coverage
id: run-tests
run: bash scripts/stack-frontend/test.sh
run: bash scripts/frontend/test.sh

- name: Upload frontend coverage artifacts
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
Expand Down
27 changes: 27 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,33 @@ All notable changes to this project are documented in this file. Format follows

For narrative release notes written for operators and product owners, see [RELEASE_NOTES.md](RELEASE_NOTES.md).

## [1.0.2] - 2026-06-29

Second patch on the 1.0.0 single-stack architecture. Headlined by **restoring tool use in assistant chats** (reverting the 1.0.0 knowledge-base-only change), plus a CodeQL security-hardening sweep, remediation of 6 Dependabot alerts, and a nightly-pipeline fix. No migration; upgrade in place.

### ✨ Improved

- **Assistants can use tools again** — reverts the 1.0.0 knowledge-base-only restriction (#382). The inference API no longer forces `enabled_tools=[]` on assistant turns and the "Knowledge Base Grounding / no external tools" directive is removed from the system prompt, so the user's selected MCP/tools flow through to assistant chats again. KB context is still pre-stuffed into the user message and assistant instructions still apply. The editor preview now forwards the owner's enabled tools and renders tool-use cards, matching consumer chat. Assistant chats emit tool-use (and MCP-App) events again (#517)

### 🐛 Fixed

- Nightly coverage pipeline: `test-backend`, `test-frontend`, and `install-frontend` jobs failed with "No such file or directory" after the single-stack refactor removed `scripts/stack-app-api/` and `scripts/stack-frontend/`; repointed `nightly.yml` to the sanctioned `scripts/backend/test.sh`, `scripts/frontend/install.sh`, and `scripts/frontend/test.sh` (behavior preserved 1:1) (#518)

### 🔒 Security

- **HIGH `py/incomplete-url-substring-sanitization`** — `external_mcp_client` now parses the URL host (`urlparse`) and matches an anchored suffix instead of substring-checking the whole URL, so an AWS marker in a path/query/userinfo can no longer trick SigV4 signing into attaching IAM credentials to a non-AWS host (#521)
- **HIGH `js/regex/missing-regexp-anchor`** — `admin-tool.model` parses the host (`new URL`) and anchors the AWS-endpoint regexes (`$`), preventing spoofed-host matches (#521)
- **MEDIUM `py/log-injection`** (24 sites across 16 files) — new `apis.shared.security.scrub_log()` neutralizes CR/LF/control characters; applied to every flagged user-controlled log value (#521)
- **MEDIUM `actions/untrusted-checkout`** — added `persist-credentials: false` to all `inputs.ref` checkouts in `nightly-deploy-pipeline.yml` (#521)
- **WARNING `py/regex/duplicate-in-character-class`** — removed a stray `[` from a `re.VERBOSE` comment that the parser misread as a character class (#521)
- Added regression tests: `TestAwsUrlHostSanitization`, `admin-tool.model.spec.ts` (13 cases), `test_log_sanitize.py` (#521)

### 📦 Dependencies

- **docs-site:** `astro` 6.3.1 → 6.4.8 (reflected XSS via slot name GHSA-8hv8-536x-4wqp, host-header SSRF GHSA-2pvr-wf23-7pc7, spread-attribute XSS GHSA-jrpj-wcv7-9fh9); `esbuild` → 0.28.1 via overrides (dev-server arbitrary file read GHSA-g7r4-m6w7-qqqr)
- **frontend:** `esbuild` → 0.28.1 via overrides (transitive through `@angular/build` 21.2.16; GHSA-g7r4-m6w7-qqqr)
- **backend:** `pydantic-settings` 2.13.1 → 2.14.2 (transitive; `NestedSecretsSettingsSource` symlink traversal / local file read GHSA-4xgf-cpjx-pc3j) (#520)

## [1.0.1] - 2026-06-26

First patch on top of the 1.0.0 general-availability release. Adds the ability to **save a conversation to a connected app** ("Save to…", with Google Drive as the reference export target) and **support for external (cross-account) Route53 hosted zones**. Both additions are additive and off by default until configured; existing 1.0.0 deployments upgrade in place with no migration.
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
**An open-source, production-ready Generative AI platform for institutions**
*Built by Boise State University, designed for everyone.*

[![Release](https://img.shields.io/badge/Release-v1.0.1-6366f1?style=flat&logo=github&logoColor=white)](RELEASE_NOTES.md)
[![Release](https://img.shields.io/badge/Release-v1.0.2-6366f1?style=flat&logo=github&logoColor=white)](RELEASE_NOTES.md)
[![Nightly](https://github.com/Boise-State-Development/agentcore-public-stack/actions/workflows/nightly.yml/badge.svg)](https://github.com/Boise-State-Development/agentcore-public-stack/actions/workflows/nightly.yml)

![Python](https://img.shields.io/badge/Python-3.13+-3776AB?style=flat&logo=python&logoColor=white)
Expand Down Expand Up @@ -296,7 +296,7 @@ agentcore-public-stack/

See [RELEASE_NOTES.md](RELEASE_NOTES.md) for the full changelog, including new features, bug fixes, platform upgrades, and deployment notes for each release.

**Current release:** v1.0.1
**Current release:** v1.0.2

---

Expand Down
70 changes: 70 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,73 @@
# Release Notes — v1.0.2

**Release Date:** June 29, 2026
**Previous Release:** v1.0.1 (June 26, 2026)

---

> ⚠️ **Coming from a pre-1.0.0 (beta) deployment? Read the 1.0.0 release notes first.** There is **no special upgrade path for 1.0.2 itself** — if you're already on 1.0.0 or 1.0.1 you upgrade in place with no migration. But 1.0.0 was the single-stack consolidation, and upgrading **from any beta** to 1.0.0 (and therefore to 1.0.2) is a **destructive backup → teardown → redeploy → restore migration**, not an in-place `cdk deploy`. If you haven't already worked through it, do that before deploying 1.0.2: see [**Upgrading an existing deployment** (1.0.0 notes)](#upgrading-an-existing-deployment) below, or the published guide at <https://boise-state-development.github.io/agentcore-public-stack/deployment/upgrade/>. **Brand-new deployments need none of this.**

---

## Highlights

v1.0.2 is a small, security-focused patch on the 1.0.0 single-stack architecture with one notable behavior change. The headline is that **assistants can use tools again**: 1.0.0 had locked assistant chats to a knowledge-base-only, tool-free mode (#382), and this release reverts that so an assistant can once more leverage the user's selected MCP and built-in tools. Alongside it, this release lands a **CodeQL security-hardening sweep** (two HIGH findings around URL/host validation, a log-injection pass across 24 call sites, and a hardened CI checkout), remediates **6 Dependabot alerts** (Astro XSS/SSRF, esbuild dev-server file read, pydantic-settings path traversal), and fixes the **nightly coverage pipeline** that broke when the single-stack refactor moved its scripts. There is **no migration** — operators on 1.0.0 or 1.0.1 upgrade in place.

---

## Assistants can use tools again

1.0.0 introduced a deliberate restriction: assistant ("RAG") chats ran knowledge-base-grounded with **zero external tools** — the inference API forced `enabled_tools=[]` on assistant turns and the system prompt told the model it had no external tools (#382). That made assistants safe and predictable but also meant they couldn't search the web, hit an MCP server, or run code even when the user had those tools enabled. v1.0.2 reverts the restriction so assistants behave like a normal chat with the assistant's knowledge and instructions layered on top.

What stays the same: knowledge-base context is still pre-stuffed into the user message, and the assistant's custom instructions still apply. What changes: the user's tool-picker selection now flows through to the agent on assistant turns, and assistant chats once again emit tool-use and MCP-App events.

### Backend

- `inference_api/chat/routes.py` — dropped the `enabled_tools=[]` override in the `rag_assistant_id` branch so the client's tool selection reaches the agent, and removed the "Knowledge Base Grounding / no external tools" directive from both the with-instructions and no-instructions system-prompt paths (restoring the pre-#382 prompt composition).

### Frontend

- `chat-request.service.ts` — no longer force-sends `enabled_tools=[]` on assistant turns; the user's tool-picker selection rides along (skills mode stays gated on non-assistant turns).
- `preview-chat.service.ts` — the editor preview now forwards the owner's enabled tools instead of `[]`, and builds the streaming assistant message as ordered content blocks (text interleaved with tool use) wired to `onToolUse`/`onToolResult`, so the shared message-list renders tool cards in the preview exactly like a consumer chat.

### Test coverage

Specs updated to assert tools are forwarded on both assistant and preview turns (`chat-request.service.spec.ts`, `preview-chat.service.spec.ts`).

## 🐛 Bug fixes

- **Nightly coverage pipeline was failing.** The single-stack refactor removed `scripts/stack-app-api/` and `scripts/stack-frontend/`, but `nightly.yml`'s `test-backend`, `test-frontend`, and `install-frontend` jobs still called them, so they died with "No such file or directory." The three scripts were ported to the sanctioned post-refactor layout — `scripts/backend/test.sh`, `scripts/frontend/install.sh`, and `scripts/frontend/test.sh` — with behavior preserved 1:1 (uv install/sync + `pytest --cov`; `npm ci` for frontend and infra; `ng test --no-watch --coverage`). (#518)

## 🔒 Security

This release closes a CodeQL sweep (#521) and 6 Dependabot alerts (#520), each with regression tests where applicable.

**CodeQL code findings (#521):**

- **HIGH `py/incomplete-url-substring-sanitization`** — `external_mcp_client` previously substring-checked the whole URL for an AWS marker before deciding to SigV4-sign. A crafted URL with the marker in a path, query, or userinfo segment could trick it into attaching IAM credentials to a non-AWS host. It now parses the host with `urlparse` and matches an **anchored suffix**. Covered by `TestAwsUrlHostSanitization` (adversarial URLs).
- **HIGH `js/regex/missing-regexp-anchor`** — `admin-tool.model` now parses the host via `new URL` and **anchors** the AWS-endpoint regexes (`$`) so a spoofed host can't satisfy the match. Covered by `admin-tool.model.spec.ts` (13 cases including spoofed hosts).
- **MEDIUM `py/log-injection`** (24 sites across 16 files) — a new `apis.shared.security.scrub_log()` helper neutralizes CR/LF and control characters; every flagged user-controlled log value is now wrapped. Covered by `test_log_sanitize.py`.
- **MEDIUM `actions/untrusted-checkout`** — all `inputs.ref` checkouts in `nightly-deploy-pipeline.yml` now set `persist-credentials: false`.
- **WARNING `py/regex/duplicate-in-character-class`** — removed a stray `[` from a `re.VERBOSE` comment that the regex parser misread as a character class.

**Dependency CVE remediation (#520):**

| Component | Package | From | To | Fix |
|---|---|---|---|---|
| docs-site | `astro` | 6.3.1 | 6.4.8 | Reflected XSS via slot name, host-header SSRF in prerendered error page, spread-attribute XSS |
| docs-site | `esbuild` | — | 0.28.1 (override) | Dev-server arbitrary file read (GHSA-g7r4-m6w7-qqqr) |
| frontend | `esbuild` | — | 0.28.1 (override) | Dev-server arbitrary file read (transitive via `@angular/build` 21.2.16) |
| backend | `pydantic-settings` | 2.13.1 | 2.14.2 | `NestedSecretsSettingsSource` symlink traversal / local file read (GHSA-4xgf-cpjx-pc3j) |

## 🚀 Deployment notes

v1.0.2 is a patch on the single-stack `PlatformStack` architecture. Operators on 1.0.0 or 1.0.1 upgrade in place — **no migration, no new infrastructure, no new env vars.**

- **Behavior change to be aware of:** after deploying, assistant chats will once again use whatever tools the user has enabled (web search, MCP servers, code interpreter, etc.) rather than running knowledge-base-only. If your deployment relied on assistants being tool-free, note that this 1.0.0 restriction has been intentionally reverted.
- The security and dependency fixes require no operator action beyond deploying the new images/SPA build.

---

# Release Notes — v1.0.1

**Release Date:** June 26, 2026
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.0.1
1.0.2
2 changes: 1 addition & 1 deletion backend/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "agentcore-stack"
version = "1.0.1"
version = "1.0.2"
requires-python = ">=3.10"
description = "Multi-agent conversational AI system with AWS Bedrock AgentCore"
readme = "README.md"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ def _parse_sheet_inventory(bootstrap_stdout: str) -> Dict[str, Any]:
if isinstance(names, list):
result["skipped_preview"] = [str(n) for n in names]
except (ValueError, SyntaxError):
# Best-effort parse — ignore malformed preview metadata.
pass
elif stripped.startswith("sheet|"):
parts = stripped.split("|")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

from apis.shared.files.models import is_tabular_file

from apis.shared.security.log_sanitize import scrub_log

logger = logging.getLogger(__name__)


Expand Down Expand Up @@ -121,7 +123,7 @@ def _query() -> Dict[str, Any]:
return files

except Exception as e:
logger.error(f"Error querying KB files for assistant {assistant_id}: {e}")
logger.error(f"Error querying KB files for assistant {scrub_log(assistant_id)}: {scrub_log(e)}")
return []


Expand Down Expand Up @@ -154,5 +156,5 @@ async def _get_session_files(session_id: str) -> List[Dict[str, Any]]:
return files

except Exception as e:
logger.error(f"Error querying session files for {session_id}: {e}")
logger.error(f"Error querying session files for {scrub_log(session_id)}: {scrub_log(e)}")
return []
4 changes: 3 additions & 1 deletion backend/src/agents/main_agent/agent_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

from agents.main_agent.base_agent import BaseAgent

from apis.shared.security.log_sanitize import scrub_log

logger = logging.getLogger(__name__)


Expand Down Expand Up @@ -47,7 +49,7 @@ def create_agent(agent_type: str = "chat", **kwargs) -> BaseAgent:
available = ", ".join(sorted(_AGENT_TYPES.keys()))
raise ValueError(f"Unknown agent_type '{agent_type}'. Available: {available}")

logger.info(f"Creating {agent_type} agent ({agent_class.__name__})")
logger.info(f"Creating {scrub_log(agent_type)} agent ({agent_class.__name__})")
return agent_class(**kwargs)


Expand Down
Loading
Loading