Skip to content

Add pack+sideload Teams app script to activity-protocol postdeploy (#9172)#9188

Open
v1212 wants to merge 22 commits into
Azure:mainfrom
v1212:users/wujia/activity-teams-sideload-9172
Open

Add pack+sideload Teams app script to activity-protocol postdeploy (#9172)#9188
v1212 wants to merge 22 commits into
Azure:mainfrom
v1212:users/wujia/activity-teams-sideload-9172

Conversation

@v1212

@v1212 v1212 commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Summary

Purely additive enhancement (issue #9172). For activity-protocol agents, azd deploy already writes TEAMS_APP_SETUP.md next to the agent source. This PR also emits a runnable pack-and-sideload script (pack-and-sideload-teams-app.ps1 and .sh) so the user can go from a fresh deploy to a Teams-installed app with one command, instead of following the manual guide steps.

What the script does

  • Builds the Teams app package with the bot id baked in from the deploy (no manual editing).
  • Installs it for the current user via atk install --scope Personal — no Teams admin / org catalog needed.
  • Checks for and installs the atk CLI (npm) if missing; launches atk auth login when not signed in.
  • Embeds the required color/outline icons.
  • Idempotent: a stable per-agent Teams app id (UUIDv5 of the bot id) means re-runs update the same app rather than duplicating.
  • Honors SKIP_TEAMS_INSTALL=1 to only build the package.

The guide now points to the script as the fast path and lists its prerequisites.

Additive / no behavior change

  • No change to existing bot provisioning or guide generation. The script is written alongside the existing guide in the activity postdeploy path only.
  • Touched listen_activity.go only to call the new writer and pass the script path into the existing printTeamsNextSteps pointer.

Testing

  • go build ./..., go vet ./..., go test ./internal/cmd/ all green.
  • Both scripts smoke-tested end-to-end with a fake atk shim: manifest botId == msaAppID, deterministic app id, valid icons, zip entries at package root.
  • atk auth login m365 verified against atk 1.1.11.

Closes #9172

…zure#9172)

For activity-protocol agents, `azd deploy` already writes TEAMS_APP_SETUP.md.
This additive change also emits a runnable pack-and-sideload script
(pack-and-sideload-teams-app.ps1 and .sh) next to the agent source. The
script builds the Teams app package with the bot id baked in from the
deploy and installs it for the current user via
`atk install --scope Personal` (no Teams admin required) in one command.

It checks for and installs the atk CLI, launches `atk auth login` when
needed, embeds the required icons, is idempotent (a stable per-agent Teams
app id means re-runs update the same app instead of duplicating), and
honors SKIP_TEAMS_INSTALL=1. The guide now points to the script as the
fast path and lists its prerequisites.

Purely additive: no change to existing bot provisioning or guide behavior.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 7b480c5f-6c14-4d28-a19a-634f28621671
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).
21 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@github-actions github-actions Bot added the ext-agents azure.ai.agents extension label Jul 17, 2026
Split the two base64 icon constants into <=150-char chunks joined with '+'
to satisfy the lll (line-length 220) linter; reassembled value is identical.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 7b480c5f-6c14-4d28-a19a-634f28621671
@v1212
v1212 marked this pull request as ready for review July 17, 2026 08:56
Copilot AI review requested due to automatic review settings July 17, 2026 08:56
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).
21 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

Wrap the icon base64 const block with cspell:disable/enable so the encoded
PNG data does not trip the spell checker.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 7b480c5f-6c14-4d28-a19a-634f28621671

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds generated Teams packaging and sideloading scripts for activity-protocol agents.

Changes:

  • Generates Bash and PowerShell scripts with deterministic app IDs and embedded icons.
  • Integrates scripts into postdeploy guidance.
  • Adds tests, documentation, and a changelog entry.

Reviewed changes

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

Show a summary per file
File Description
teams_sideload_script.go Generates and selects sideload scripts.
teams_sideload_script_test.go Tests script generation and IDs.
listen_activity.go Adds scripts to postdeploy output.
teams_pack_sideload.sh Bash packaging and installation flow.
teams_pack_sideload.ps1 PowerShell packaging and installation flow.
teams_app_setup_guide.md Documents the generated scripts.
CHANGELOG.md Records the enhancement.

Comment thread cli/azd/extensions/azure.ai.agents/internal/cmd/assets/teams_pack_sideload.sh Outdated
Comment thread cli/azd/extensions/azure.ai.agents/internal/cmd/assets/teams_pack_sideload.sh Outdated
Comment thread cli/azd/extensions/azure.ai.agents/internal/cmd/assets/teams_pack_sideload.sh Outdated
Comment thread cli/azd/extensions/azure.ai.agents/internal/cmd/assets/teams_pack_sideload.ps1 Outdated
Comment thread cli/azd/extensions/azure.ai.agents/internal/cmd/assets/teams_pack_sideload.ps1 Outdated
Comment thread cli/azd/extensions/azure.ai.agents/internal/cmd/listen_activity.go Outdated
Comment thread cli/azd/extensions/azure.ai.agents/CHANGELOG.md Outdated
Copilot AI review requested due to automatic review settings July 17, 2026 09:05

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

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

Comment thread cli/azd/extensions/azure.ai.agents/internal/cmd/assets/teams_pack_sideload.sh Outdated
Comment thread cli/azd/extensions/azure.ai.agents/internal/cmd/assets/teams_pack_sideload.sh Outdated
Comment thread cli/azd/extensions/azure.ai.agents/internal/cmd/assets/teams_pack_sideload.sh Outdated
Comment thread cli/azd/extensions/azure.ai.agents/internal/cmd/assets/teams_pack_sideload.ps1 Outdated
Comment thread cli/azd/extensions/azure.ai.agents/internal/cmd/assets/teams_pack_sideload.ps1 Outdated
Comment thread cli/azd/extensions/azure.ai.agents/internal/cmd/listen_activity.go Outdated
Comment thread cli/azd/extensions/azure.ai.agents/CHANGELOG.md Outdated
- teams_pack_sideload.{sh,ps1}: move the SKIP_TEAMS_INSTALL guard to after the
  package is built so it is a true build-only mode (was skipping packaging).
- Bound Teams manifest name.short (<=30) and description.short (<=80) per v1.19,
  since agent names may be up to 63 chars.
- sh: make the TitleId grep tolerate no match (|| true) so the manual-sideload
  fallback stays reachable under 'set -euo pipefail'.
- listen_activity.go: emit a shell-safe run hint via sideloadRunCommand (quotes
  the path, pwsh call operator for .ps1) per cli/azd/AGENTS.md.
- Remove the CHANGELOG entry; per azure.ai.agents/AGENTS.md the CHANGELOG is
  only updated in the dedicated version-bump release PR.
- Add tests for build-only ordering, manifest-field truncation, fallback
  reachability, and shell-safe run command.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 7b480c5f-6c14-4d28-a19a-634f28621671
Copilot AI review requested due to automatic review settings July 17, 2026 09:25

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 7 comments.

Comment thread cli/azd/extensions/azure.ai.agents/internal/cmd/assets/teams_pack_sideload.sh Outdated
Comment thread cli/azd/extensions/azure.ai.agents/internal/cmd/assets/teams_pack_sideload.sh Outdated
Comment thread cli/azd/extensions/azure.ai.agents/internal/cmd/assets/teams_pack_sideload.sh Outdated
Comment thread cli/azd/extensions/azure.ai.agents/internal/cmd/assets/teams_pack_sideload.ps1 Outdated
Comment thread cli/azd/extensions/azure.ai.agents/internal/cmd/assets/teams_pack_sideload.ps1 Outdated
Comment thread cli/azd/extensions/azure.ai.agents/internal/cmd/assets/teams_pack_sideload.ps1 Outdated
Comment thread cli/azd/extensions/azure.ai.agents/internal/cmd/teams_sideload_script.go Outdated
Assemble expected values from the input path instead of a single long string
literal so gosec no longer flags the test as a potential hardcoded credential.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 7b480c5f-6c14-4d28-a19a-634f28621671
Copilot AI review requested due to automatic review settings July 17, 2026 09:37

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.

Comment thread cli/azd/extensions/azure.ai.agents/internal/cmd/listen_activity.go Outdated
Round-9 review: len(scriptPaths) > 0 treated a partial write as success. If the
current-OS script name collided with a user-owned file but the other script was
written, preferredSideloadScript returned empty, the collision note was
suppressed, and the guide still advertised both filenames -- including the
unrelated user file.

Gate scriptsGenerated on len(scriptPaths) == teamsSideloadTargets (a new const =
the number of shells scripted), so the guide/output only advertise the fast path
when every promised script was actually generated; a partial write now shows the
collision note and the manual steps. printTeamsNextSteps only prints the fast
path when scriptsGenerated is true. Tests assert the happy path equals
teamsSideloadTargets and a name collision yields a sub-target partial write.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 7b480c5f-6c14-4d28-a19a-634f28621671
Copilot AI review requested due to automatic review settings July 17, 2026 12:24

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.

Comment thread cli/azd/extensions/azure.ai.agents/internal/cmd/listen_activity.go Outdated
Comment thread cli/azd/extensions/azure.ai.agents/internal/cmd/assets/teams_app_setup_guide.md Outdated
Round-10 review:

- printTeamsNextSteps: when the fast path was suppressed (partial write) and the
  guide also failed to write, the manual fallback was skipped because it keyed off
  scriptPath == "" rather than whether a next action had been shown. Track
  fastPathShown and print the inline manual steps whenever the guide is missing
  and the fast path was not advertised, so the user is never left without a next
  action pointing at an unwritten guide.

- teams_app_setup_guide.md: the PowerShell build-only example set
  $env:SKIP_TEAMS_INSTALL for the whole session, so a later normal run in the same
  terminal silently stayed in build-only mode. Wrap it in try/finally that clears
  the variable after the one run (including on failure); the bash form is already
  per-command.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 7b480c5f-6c14-4d28-a19a-634f28621671
Copilot AI review requested due to automatic review settings July 17, 2026 12:47

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

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

Comment thread cli/azd/extensions/azure.ai.agents/internal/cmd/assets/teams_pack_sideload.sh Outdated
Comment thread cli/azd/extensions/azure.ai.agents/internal/cmd/assets/teams_pack_sideload.ps1 Outdated
…ripts

Address Copilot review round 11 on PR Azure#9188:

- Version idempotency: the previous time-derived version only advanced
  every 2 seconds, so two valid reruns in the same 2-second bucket produced
  the SAME version and Teams rejected the second update. Persist a monotonic
  build number next to the script (.teams-app-version), seeded from wall-clock
  seconds but always at least last + 1, so every rerun is strictly higher --
  even within the same second or after a backwards clock adjustment. It is
  encoded into two bounded components (minor = N/65536, patch = N%65536) so
  each stays <= 65535 (minor < 65535 until ~2106). Applied to both the pwsh
  and bash scripts.

- Chmod failure: writeTeamsSideloadScripts still appended a script to the
  generated list when os.Chmod failed, so the guide could advertise a script
  the user cannot execute. On chmod failure, skip the target so it counts as
  not-generated and the manual fallback is shown instead.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 7b480c5f-6c14-4d28-a19a-634f28621671
Copilot AI review requested due to automatic review settings July 17, 2026 13:07

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 5 comments.

Comment thread cli/azd/extensions/azure.ai.agents/internal/cmd/assets/teams_pack_sideload.sh Outdated
Comment thread cli/azd/extensions/azure.ai.agents/internal/cmd/assets/teams_pack_sideload.sh Outdated
Comment thread cli/azd/extensions/azure.ai.agents/internal/cmd/assets/teams_pack_sideload.ps1 Outdated
Comment thread cli/azd/extensions/azure.ai.agents/internal/cmd/assets/teams_pack_sideload.ps1 Outdated
Comment thread cli/azd/extensions/azure.ai.agents/internal/cmd/assets/teams_app_setup_guide.md Outdated
Address Copilot review round 12 on PR Azure#9188:

- Symlink safety: the .teams-app-version counter lived in the user-controlled
  service directory, and a pre-existing symlink there would be followed and its
  target truncated when the generated script ran -- letting a planted link
  overwrite an arbitrary user-writable file. Both scripts now refuse to read
  from or write through a symlink / reparse point / directory: the read is
  gated on a plain regular file, and the write goes to a temp file that is
  atomically moved into place (replacing the link itself, never its target).
  On such a collision the counter is simply not persisted and the time-derived
  version is used.

- atk login command: several user-facing messages and the guide prerequisite
  referred to the bare parent command 'atk auth login', which does not start a
  sign-in on the current CLI. They now use the concrete 'atk auth login m365'
  invocation the scripts already run.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 7b480c5f-6c14-4d28-a19a-634f28621671
Copilot AI review requested due to automatic review settings July 17, 2026 13:27

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.

Comment thread cli/azd/extensions/azure.ai.agents/internal/cmd/assets/teams_pack_sideload.sh Outdated
Comment thread cli/azd/extensions/azure.ai.agents/internal/cmd/assets/teams_pack_sideload.ps1 Outdated
Address Copilot review round 13 on PR Azure#9188:

The current ATK CLI prints "Cannot get token. Use 'atk account login m365'
to log in the correct account." when no M365 account is signed in. The
login-detection regex in both generated scripts did not match that wording,
so a fresh user skipped the promised automatic login and fell straight through
to the install-failed guidance.

- Extend the bash (ERE) and pwsh (.NET) login-required patterns with
  'cannot get token' and 'log in the correct account'.
- Add TestTeamsSideloadLoginDetection: asserts an equivalent pattern matches
  the real ATK unauthenticated error and not a successful install line, and
  that both embedded scripts carry the covering phrases.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 7b480c5f-6c14-4d28-a19a-634f28621671
Copilot AI review requested due to automatic review settings July 17, 2026 13:51

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.

Address Copilot review round 14 on PR Azure#9188:

The pack+sideload scripts, setup guide, and version-state file used fixed
names. If two activity services resolve to the same project: source directory,
each postdeploy recognized the same generic marker and overwrote the other's
scripts/guide with its own bot id -- both services then advertised one path
but only the last agent's package installed (and it raced under parallel,
graph-driven deploy).

- Make the generated marker agent-specific ("... for bot <msaAppId>") and add
  canWriteGeneratedFile, which only (over)writes an absent path or a regular
  file this same agent generated. A user-owned file, a non-regular file, or a
  file another agent generated in a shared source dir is left untouched, so the
  second service reports not-generated and shows the manual fallback instead of
  clobbering the first.
- Apply the same guard to the setup guide (previously overwritten
  unconditionally).
- Scope the version-state file per Teams app id (.teams-app-version-<appId>)
  so two apps sharing a directory never cross-contaminate their version
  counters.
- Tests: refresh case now seeds this agent's marker; add
  TestWriteTeamsSideloadScriptsRejectsOtherAgent covering the shared-dir case.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 7b480c5f-6c14-4d28-a19a-634f28621671
Copilot AI review requested due to automatic review settings July 17, 2026 14:17

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 5 comments.

Comment on lines +51 to +52
func teamsGeneratedMarkerFor(msaAppID string) string {
return teamsSideloadGeneratedMarker + " for bot " + msaAppID
Comment on lines +110 to +111
func deterministicTeamsAppID(msaAppID string) string {
return uuid.NewSHA1(teamsAppIDNamespace, []byte("foundry-teams-app:"+msaAppID)).String()
// Do not clobber a user-owned file that shares this name, or a script a
// different activity service generated for another agent -- only refresh
// a regular file we generated for this same agent.
if ok, reason := canWriteGeneratedFile(scriptPath, msaAppID); !ok {
Comment on lines +167 to +169
if ok, reason := canWriteGeneratedFile(guidePath, msaAppID); !ok {
log.Printf("postdeploy: Teams setup guide %q %s", guidePath, reason)
return ""
Comment on lines +304 to +307
// TestTeamsSideloadScriptBuildOnly asserts the SKIP_TEAMS_INSTALL opt-out is a
// build-only mode: the package (zip) is produced first and only the atk install
// is skipped. It verifies this via source ordering rather than executing the
// scripts (which would need a real atk/npm/pwsh|bash on both CI OSes).
The word "unstat-able" in a code comment tripped the cspell-lint CI check.
Reword to plain English; no behavior change.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 7b480c5f-6c14-4d28-a19a-634f28621671
Copilot AI review requested due to automatic review settings July 17, 2026 14:26

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 4 comments.

Comment on lines +51 to +52
func teamsGeneratedMarkerFor(msaAppID string) string {
return teamsSideloadGeneratedMarker + " for bot " + msaAppID
Comment on lines +200 to +203
if ok, reason := canWriteGeneratedFile(scriptPath, msaAppID); !ok {
log.Printf("postdeploy: Teams sideload script %q %s", scriptPath, reason)
continue
}
Comment on lines +167 to +169
if ok, reason := canWriteGeneratedFile(guidePath, msaAppID); !ok {
log.Printf("postdeploy: Teams setup guide %q %s", guidePath, reason)
return ""
@@ -1,3 +1,4 @@
<!-- Generated by 'azd deploy' (activity protocol) for bot {{.MsaAppID}}. Safe to edit or delete. -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ext-agents azure.ai.agents extension

Projects

None yet

Development

Successfully merging this pull request may close these issues.

activity agents: emit a runnable Teams pack+sideload script alongside TEAMS_APP_SETUP.md

3 participants