Skip to content

Add opt-in API test authentication providers - #10085

Merged
Prangshuman Das (t-prda) merged 174 commits into
mainfrom
prdas/646383-api-test-auth
Sep 29, 2026
Merged

Prangshuman Das (t-prda) merged 174 commits into
mainfrom
prdas/646383-api-test-auth

Conversation

@t-prda

@t-prda Prangshuman Das (t-prda) commented Aug 10, 2026 •

Copy link
Copy Markdown
Contributor

Purpose

AB#646383

Add opt-in authentication to Library - Graph Mgt. without API re-enablement or pipeline changes.

Design

  • Default None preserves existing behavior. The public enum/interface and public API Test Auth Context retain external provider extensibility.
  • The Microsoft provider stays Internal; context Apply stays internal. Internal visibility is API encapsulation, not authorization.
  • Credential precedence remains container file, then existing Key Vault only if the file is absent. Invalid configured credentials fail; successful passwords remain instance-scoped SecretText.
  • File credentials now use a private file-mapping provider directly, without replacing or clearing the session-wide Azure Key Vault provider/cache. No extra AL plaintext copy is introduced.
  • OnAfterInitializeWebRequestWithURL remains last. The pre-existing empty Graph OnRun is restored.

The trust boundary is admitted OnPrem test code and environment credential access, not Internal visibility or a destination-URL restriction.

Tests and scope

All six AL contracts remain: default None, event ordering, provider reuse, instance scoping, same-provider reselection and deselection.
The dedicated recorder is removed. The non-SingleInstance internal mock publishes the test-only OnAfterConfigureAuthentication event; the same manually bound test-codeunit instance owns Library - Variable Storage for both recording and verification. Initialization clears that instance's queue after prior failures; each contract drains it and calls AssertEmpty.

The six source-pattern PowerShell checks are removed, not replaced by other AL-text assertions. The real 401/200/401 HTTP scenario is owned by uptake #11860 after credential provisioning; core has no dependency on that future workflow. This is not a claim of a complete provider-branch matrix.

No caller migration, URL repair, credential provisioning, scheduling, exclusion or work-date rollout belongs to this core.

Native stack #11893: #10085 auth core -> #11862 URL/fixture prerequisites -> #11891 workflow infrastructure -> #11860 AL uptake -> #11224–#11230 -> #11322 -> #11451–#11454.

Current checkpoint

Head 4a76bb71851c158083dbe4d22e84bf40a0577842, tree 12739039e502a3feeea9e98694fb360ea959c606.

Merged main baseline remains 0a602a2481c93ebfe7b1d27d6016fb9926c42111 (permission cleanup from PR 11561). No additional main merge or code changes were made during finalization. Old b195c7a/4eef8ac tree-equality claims remain obsolete after the intentional baseline/auth changes.

Verified AL compile/publish/test run 36131334134 succeeded, attempt 2, at exact validation head 4a76bb71851c158083dbe4d22e84bf40a0577842. 113/113 test jobs and 113/113 cleanup steps succeeded. Core has no credential-file provisioning/removal step (expected).

W1 artifacts verify all 6 auth contracts.

Local Pester at the applicable checkpoint: 28 passed, zero failed/skipped. Core local Pester: 28 passed; no unsupported claim about a separate root PowerShell workflow.

Validation limits

For uptake/full, CU139496 MicrosoftAuthenticationRespectsServerAuthMode is verified in the actual UserPassword fixture (401/200/401). The Windows 200/200/200 expectations are implemented but Windows runtime remains unverified; no foreign local NST was used. Successful GitHub runs do not establish universal native NAV coverage. Excluded PDF cases, country-specific absent/excluded cases and tolerated-native distinctions are not claimed passing. No PR has been merged or auto-merged; validation drafts remain Do Not Merge outside stack #11893.

@t-prda
Prangshuman Das (t-prda) requested review from a team August 10, 2026 11:01
@github-actions github-actions Bot added Build: scripts & configs Build scripts and configuration files AL: Apps (W1) Add-on apps for W1 Team: Integrations GitHub request for Integrations area labels Aug 10, 2026
@github-actions github-actions Bot added this to the Version 29.0 milestone Aug 10, 2026
Comment thread build/scripts/NewBcContainer.ps1 Fixed
Comment thread build/scripts/NewBcContainer.ps1 Fixed
Comment thread src/Layers/W1/Tests/TestLibraries/LibraryGraphAuthMgt.Codeunit.al Outdated
Comment thread src/Layers/W1/Tests/TestLibraries/LibraryGraphAuthMgt.Codeunit.al Outdated
@t-prda
Prangshuman Das (t-prda) marked this pull request as draft August 10, 2026 11:20

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

This PR centralizes Basic authentication injection for Library - Graph Mgt-based API tests so they can run in NavUserPassword (UserPassword) containers, and then re-enables several previously disabled API/E2E test suites. It replaces an app-specific Expense Agent auth helper with a shared TestLibraries subscriber and adds a container-side “credential bridge” file so the test runner can obtain the password without requiring Azure Key Vault.

Changes:

  • Added Library - Graph Auth Mgt. as an event subscriber to inject Basic auth for non-Windows test users, sourcing the password from a container file or (fallback) Azure Key Vault.
  • Removed the Expense Agent test-only auth helper + manual subscription binding; tests now rely on the shared subscriber.
  • Re-enabled multiple API/E2E test suites by removing entries from various *.DisabledTest.json files (and deleting the APIV1/APIV2 exclusion lists), and updated container provisioning to create the API-test password bridge file.

Reviewed changes

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

Show a summary per file
File Description
src/Layers/W1/Tests/TestLibraries/LibraryGraphAuthMgt.Codeunit.al New shared subscriber that injects Basic auth into Library - Graph Mgt requests for NavUserPassword scenarios.
build/scripts/NewBcContainer.ps1 Writes the container password bridge file and sets ACLs so server-side AL can read it.
src/Apps/W1/ExpenseAgent/test/src/Helper/ExpenseAPITestAuthHelper.Codeunit.al Removes app-specific auth injection helper in favor of shared TestLibraries implementation.
src/Apps/W1/ExpenseAgent/test/src/API/ExpenseUsersAPITest.Codeunit.al Drops manual subscription binding to the removed helper.
src/Apps/W1/ExpenseAgent/test/src/API/ExpenseProjectsAPITest.Codeunit.al Drops manual subscription binding to the removed helper.
src/Apps/W1/ExpenseAgent/test/src/API/ExpensePerDiemLocationsTest.Codeunit.al Drops manual subscription binding to the removed helper.
src/Apps/W1/ExpenseAgent/test/src/API/ExpenseCapabilitiesAPITest.Codeunit.al Drops manual subscription binding to the removed helper.
src/DisabledTests/Tests-Integration/Tests-Integration.DisabledTest.json Re-enables specific integration API tests by removing disable entries.
src/DisabledTests/Tests-Graph/Tests-Graph.DisabledTest.json Re-enables specific Graph E2E tests by removing disable entries.
src/DisabledTests/Sustainability_Tests/Sustainability_Tests.DisabledTest.json Re-enables Sustainability API tests by removing disable entries.
src/DisabledTests/Quality_Management-Tests/Quality_Management-Tests.DisabledTest.json Re-enables Quality Management API tests by removing disable entry.
src/DisabledTests/IRS_Forms_Tests/IRS_Forms_Tests.DisabledTest.json Re-enables IRS 1099 API test by removing disable entry.
src/DisabledTests/E-Document_Core_Tests/E-Document Core Tests.DisabledTest.json Re-enables E-Document API tests by removing disable entry.
src/DisabledTests/_Exclude_APIV2__Tests/_Exclude_APIV2__Tests.DisabledTest.json Deletes the APIV2 exclusion list (re-enables APIV2 suite).
src/DisabledTests/_Exclude_APIV1__Tests/_Exclude_APIV1__Tests.DisabledTest.json Deletes the APIV1 exclusion list (re-enables APIV1 suite).

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread build/scripts/NewBcContainer.ps1 Outdated
Comment thread build/scripts/NewBcContainer.ps1 Outdated
Comment thread src/Layers/W1/Tests/TestLibraries/LibraryGraphAuthMgt.Codeunit.al Outdated
Comment thread src/Layers/W1/Tests/TestLibraries/LibraryGraphAuthMgt.Codeunit.al Outdated
Comment thread src/Layers/W1/Tests/TestLibraries/LibraryGraphAuthMgt.Codeunit.al Outdated
Comment thread src/Layers/W1/Tests/TestLibraries/LibraryGraphAuthMgt.Codeunit.al Outdated
Comment thread src/Layers/W1/Tests/TestLibraries/LibraryGraphAuthMgt.Codeunit.al Outdated
Comment thread build/scripts/NewBcContainer.ps1 Outdated
Comment thread src/Layers/W1/Tests/TestLibraries/LibraryGraphAuthMgt.Codeunit.al Outdated
Comment thread src/Layers/W1/Tests/TestLibraries/LibraryGraphAuthMgt.Codeunit.al Outdated
@t-prda

Copy link
Copy Markdown
Contributor Author

Agentic PR Review - Round 1

Recommendation: Accept

What this PR does

This PR adds an explicit authentication bridge for API tests that use Library - Graph Mgt. in BCApps UserPassword containers. The subscriber is manual, each affected API test codeunit opts in, Windows-authenticated NAV gates keep their existing behavior, and local NAV UserPassword runs can use the existing Key Vault secret.

The change addresses the gate difference directly. It does not change application API behavior, and it avoids making partner test code automatically depend on the BCApps credential bridge.

Suggestions

None.

Risk assessment and necessity

Risk: The change touches shared test infrastructure and re-enables many existing suites, so CI isolation and concurrency failures may still need separate gate work. The authentication subscriber itself is manually scoped and internal.

Necessity: The change is required because BCApps runs these tests with UserPassword while NAV's normal uptake gates use Windows authentication. Without the bridge, the API suites fail with 401 responses and remain disabled.


[AI-PR-REVIEW] version=1 promptVersion=1 system=github pr=10085 round=1 by=t-prda at=2026-08-12T09:27:33Z lastSha=6fe7981474d813fcafab57bc6e6fa0c429df80a5 reviewKey=e0d301ad1af589367637a08b287af9af4fb26402df7532abc2876a0a48dbabc7 suggestions=none

@github-actions github-actions Bot added the Build: Automation Workflows and other setup in .github folder label Aug 13, 2026
Retain the six AL contracts and the pre-existing Graph OnRun; remove auth source-pattern checks. Keep private file-secret lookup out of session-wide Key Vault state.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 3952f078-a881-4da8-ad96-13b727e48a91
Includes upstream permission cleanup fix #11561 and current artifact/baseline settings; preserve reviewed opt-in authentication without warning suppression.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 3952f078-a881-4da8-ad96-13b727e48a91
@t-prda

Copy link
Copy Markdown
Contributor Author

Implemented the approved Round 19 follow-ups and refreshed the stack baseline.

  • S9: 595eda2 reads the container file through a private mock secret-provider instance directly into SecretText. It never installs that provider into the session Azure Key Vault singleton or clears its cache, so both success and failure leave the existing provider intact. File-first / Key-Vault-only-when-file-absent precedence and instance caching remain unchanged.
  • S10: [API tests] Adopt shared authentication and re-enable scoped AL tests #11860 adds CU139494.MicrosoftAuthenticationIsRequiredForHttpRequest: actual service requests must return 401/200/401 for None/Microsoft/None. It fails on Windows/SaaS instead of silently passing and needs no fixture writes or new isolation. It is intentionally in uptake after credential provisioning: core cannot rely on the later workflow's random container credential file.
  • Dedicated recorder and six AL-source-pattern PowerShell checks removed. The same bound test instance owns recording, dequeue assertions, AssertEmpty and initialization/failure-boundary clearing. All six contracts and five later URL tests remain; the internal non-SingleInstance mock owns the only new test event.
  • Empty Graph OnRun restored; public context/enum/interface retained, Apply and Microsoft provider internal.

Main 0a602a2481c93ebfe7b1d27d6016fb9926c42111 (including #11561 permission cleanup) was honestly merged into core and forward-propagated through native stack #11893. All 19 review/validation branch refs were published atomically without force; no PR merged or auto-merged. #11862 retains its 18-file prerequisite patch, #11891 remains workflow-only, and #11860 owns adoption plus the real request regression.

Local Pester: core 28, workflow 95, uptake 98, zero failures/skips. Fresh GitHub AL compile/publish/test runs are started/pending; the new HTTP runtime result is not yet verified. Earlier successful trees are historical after this intentional baseline/auth update.

@github-actions

Copy link
Copy Markdown
Contributor

Issue #11561 is not valid. Please make sure you link an issue that exists, is open and is approved.

Comment thread src/Layers/W1/Tests/Misc/MockAPITestAuthProvider.Codeunit.al Outdated
@github-actions

Copy link
Copy Markdown
Contributor

Issue #11561 is not valid. Please make sure you link an issue that exists, is open and is approved.

Rename invocation, test-only publisher and subscriber to OnAfterConfigureAuthentication. No production event or behavior changes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 3952f078-a881-4da8-ad96-13b727e48a91
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 3952f078-a881-4da8-ad96-13b727e48a91
Convert the public dummy label through Text before assigning SecretText, matching the previously compiled fixture.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 3952f078-a881-4da8-ad96-13b727e48a91
@alexei-dobriansky

Copy link
Copy Markdown
Contributor

Good Sense Reviewer - Round 20

Recommendation: Accept with Suggestions

What this PR does

This round isolates container credential reading from the session-wide Azure Key Vault provider and moves authentication-call recording into the manually bound test instance. It also restores the required namespace and typed conversion needed by the new credential and mock-provider code.

The private file-mapping provider addresses the shared-state problem from the previous round: it reads the configured file without replacing or clearing the existing provider or cache. Authentication is still applied through the existing Http Web Request Mgt.AddBasicAuthentication path before the final request event, and no BaseApp event publisher or timing contract is changed.

Status of previous suggestions
ID Title Status Author response
S1 Separate the production report change Addressed The unrelated production change is not in the net PR diff.
S2 Cache the mock Key Vault setup Addressed Successful credentials remain cached on the retained provider instance.
S3 Keep the affected-app test exact Addressed Caller migration and suite enablement remain outside this narrowed change.
S4 Clarify the E-Doc Graph variables Addressed The related caller changes are not in the net PR diff.
S5 Clean up the container password file Addressed Credential-file provisioning and cleanup are outside this authentication core.
S6 Narrow the transient error match Addressed Retry and test-runner error handling are outside this narrowed change.
S7 Use separate clean-test result files Addressed Clean-tenant execution and result aggregation are outside this narrowed change.
S8 Plaintext SecureString fixture fails code scanning Addressed The affected PowerShell credential fixture is not in the net PR diff.
S9 Restore Key Vault provider after container read Addressed The file is now read through a private provider without changing the session provider or cache.
S10 Verify authentication reaches the request Disputed A later stacked change will validate the real 401/200/401 request sequence after credential provisioning; this PR still has no direct request assertion.
New observations (commits since round 19)

None. The new commits address the shared Key Vault state and test-recorder design without introducing another material issue.

Risk assessment and necessity

Risk: Existing callers retain the None default, and authentication remains opt-in per Library - Graph Mgt. instance. The private credential reader removes the main shared-session risk. The remaining non-blocking risk is test coverage: the tests verify provider selection, reuse, deselection, and event ordering, but the real request effect is deferred to a later stacked change. Exact-head AL builds are still running, with no current failures.

Necessity: UserPassword test environments need reusable request credentials while Windows and SaaS environments preserve ambient authentication. This is a focused and necessary foundation, although caller migration and actual API-suite enablement remain later work.

[AI-PR-REVIEW] version=1 promptVersion=4 system=github pr=10085 round=20 by=alexei-dobriansky at=2026-09-25T12:16:59Z lastSha=4a76bb71851c158083dbe4d22e84bf40a0577842 reviewKey=0577eb8ed2c6a9365605230f229eba81e04e4359c42b5147fcbed60db9b05fd6 suggestions=S9@9a9e057a:addressed,S10@b5b6666a:disputed parentRound=19

@t-prda

Copy link
Copy Markdown
Contributor Author

Final validation update for Round20/S10 (supersedes the earlier pending-runtime comment):

  • Auth core4a76bb71851c158083dbe4d22e84bf40a0577842: AL run36131334134 succeeded (attempt2), all6 auth contracts verified.
  • The real-request assertion intentionally remains uptake-owned after credential provisioning, not in the core. CU139496 MicrosoftAuthenticationRespectsServerAuthMode passed its actual UserPassword401/200/401 sequence in uptake run36162562150 at f846c7b and full run36162564729 at da6d82d; both succeeded (attempt2). Windows200/200/200 is implemented, but Windows runtime is still unverified.
  • All four final AL runs succeeded, each with113 test jobs and cleanup steps. Core has no credential-file step; workflow/uptake/full each verified113 credential removals.
  • Private Key Vault reading preserves session provider/cache; bound test-owned queue and non-SingleInstance test-only OnAfterConfigureAuthentication mock remain. The empty Graph OnRun is retained and six source-pattern auth checks stay removed. No production/public test event was added.

S10 is therefore validated at its approved stack boundary; no additional core source change is proposed. Exact-head details and native/PDF/exclusion limits are now in the PR descriptions.

@alexei-dobriansky

Copy link
Copy Markdown
Contributor

Good Sense Reviewer - Reply

Thanks for the details. Response to your point:

  • S10 - Agree. The core applies the configured Basic authentication before the final request event, while the credential-provisioned uptake test verifies the real 401/200/401 request sequence. This is the correct stack boundary, so I withdraw this point.

[AI-PR-REPLY] version=1 promptVersion=4 system=github pr=10085 reviewRound=20 by=alexei-dobriansky at=2026-09-27T12:05:45Z respondsTo=2026-09-27T10:32:43Z reviewKey=0577eb8ed2c6a9365605230f229eba81e04e4359c42b5147fcbed60db9b05fd6

@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Stale Status Check Deleted

The Pull Request Build workflow run for this PR was older than 72 hours and has been deleted.

📋 Why was it deleted?

Status checks that are too old may no longer reflect the current state of the target branch. To ensure this PR is validated against the latest code and passes up-to-date checks, a fresh build is required.


🔄 How to trigger a new status check:

  1. 📤 Push a new commit to the PR branch, or
  2. 🔁 Close and reopen the PR

This will automatically trigger a new Pull Request Build workflow run.

@github-actions github-actions Bot added Team: Integrations GitHub request for Integrations area and removed Team: SCM GitHub request for SCM area labels Sep 29, 2026
@t-prda
Prangshuman Das (t-prda) added this pull request to the merge queue Sep 29, 2026
Merged via the queue into main with commit e20f196 Sep 29, 2026
189 checks passed
@t-prda
Prangshuman Das (t-prda) deleted the prdas/646383-api-test-auth branch September 29, 2026 18:43
pull Bot pushed a commit to CarstenMertes/BCApps that referenced this pull request Sep 29, 2026
## Scope


[AB#646383](https://dynamicssmb2.visualstudio.com/Dynamics%20SMB/_workitems/edit/646383)

Prerequisite layer above microsoft#10085. Move existing **non-authentication**
repairs out of the auth-only base so reviewers can assess them
separately.

- Query-safe Graph URL path/query helpers and
`CreateTargetURLWithTwoSubpages`, with five existing URL regressions.
- Corresponding URL composition changes in API callers.
- Existing APIV2 RapidStart fixture/polling, journal-handler and
Foundation-setup corrections.
- Existing Expense Activity/Policy API fixture and assertion
corrections.
- Existing Czech inventory-posting fixture corrections, also tracked by
microsoft#11370.
- Three existing fixture-variable relocations, retained without claiming
separate product bugs.

No provider-adoption calls, work-date rollout, `RequiredTestIsolation`
changes, pipeline configuration or exclusion changes belong to this
layer. The old Expense auth helper and bindings remain until uptake.

## Dependency and validation

This PR remains the separate 18-file prerequisite above microsoft#10085; its
owned patch is unchanged by the main refresh. The five URL tests remain
alongside the six core contracts in CU139494 (11 methods). Workflow
microsoft#11891 follows it without changing AL source; AL adoption remains
microsoft#11860. No exclusions or pipeline files change here.

The root core's queue/KV fixes are inherited, not duplicated. Standalone
feature-base checks are distinct from main-targeted workflow/uptake/full
validation; none of the previous successful cumulative runs is new-head
proof.

## Current checkpoint

Head `768a6395f186f4db4981631dbcacaa01677c5d40`, tree
`0bea3b816388c79fb950a8ad22bb11ff0f2598be`.

Merged main baseline remains `0a602a2481c93ebfe7b1d27d6016fb9926c42111`
(permission cleanup from PR 11561). No additional main merge or code
changes were made during finalization. Old `b195c7a`/`4eef8ac`
tree-equality claims remain obsolete after the intentional baseline/auth
changes.

[Verified AL compile/publish/test run
36157073629](https://github.com/microsoft/BCApps/actions/runs/36157073629)
**succeeded, attempt 1**, at exact validation head
`9269e3df582704881a898e19029308e9296cbbf1`. **113/113 test jobs and
113/113 cleanup steps succeeded.** **113/113 credential-removal steps**
also succeeded.

W1 artifacts verify all **11 auth/URL methods**. Clean-codeunit
activation remains absent/off; ordinary execution, Legacy and the Unit
Disabled fallback are preserved. This prerequisite is validated as part
of the successful workflow cumulative head, not by a claimed standalone
prerequisite run.

Local Pester at the applicable checkpoint: **28 passed, zero
failed/skipped**. [PowerShell run
36157073348](https://github.com/microsoft/BCApps/actions/runs/36157073348)
**succeeded, attempt 1**.

## Validation limits

For uptake/full, CU139496
`MicrosoftAuthenticationRespectsServerAuthMode` is verified in the
actual UserPassword fixture (**401/200/401**). The Windows
**200/200/200** expectations are implemented but **Windows runtime
remains unverified**; no foreign local NST was used. Successful GitHub
runs do not establish universal native NAV coverage. Excluded PDF cases,
country-specific absent/excluded cases and tolerated-native distinctions
are not claimed passing. No PR has been merged or auto-merged;
validation drafts remain Do Not Merge outside stack #11893.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 3952f078-a881-4da8-ad96-13b727e48a91
Andres Salazar (asalazargeeky) pushed a commit to geekyllc/BCApps that referenced this pull request Oct 1, 2026
microsoft#11654)

## What and why

Consolidate the Expense Agent test repairs on current `main`, following
merged microsoft#11333.

- Fix the three Expense Mgmt. Read/Edit/Admin tests by collecting all
nine permission observations under the exact restricted role, restoring
test permissions, and only then calling Assert. No production
permissions change.
- Replace the invalid ordinary positive/negative posted-history fixture
with a normally posted zero-amount line. This preserves genuine posted
header/line history and zero recorded spend for all eight deletion,
report-recreation, and reapproval cases. Keep identity, ownership,
audit, duplicate-report and zero-spend assertions.
- Re-enable Approve/Submit/Reject Travel Request page-action tests.
Their WebServiceActionResultCode assertion compilation fix is already on
main.
- Classify codeunit 148339 as UnitTest, as requested; it exercises AL
in-process, including direct page procedures. The separate HTTP API
codeunit remains IntegrationTest.
- Repair the foreign-currency fixture in six
[AB#650247](https://dynamicssmb2.visualstudio.com/1fcb79e7-ab07-432a-a3c6-6cf5a88ba4a5/_workitems/edit/650247)
API tests (the normal rate, not the adjustment rate, must be non-unit);
refresh cross-session reads and verify persisted identities, dates and
ownership without removing negative operations.
- Remove exactly 14 role/history/action exclusions from the BCApps
Expense Agent disabled-test manifest. No exclusions remain for codeunits
148338 or 148339 in this branch.
- Preserve ALL HTTP API exclusions in BCApps, including the six
[AB#650247](https://dynamicssmb2.visualstudio.com/1fcb79e7-ab07-432a-a3c6-6cf5a88ba4a5/_workitems/edit/650247)
cases: BCApps still needs the separate API-authentication prerequisite.
The fixture corrections are retained, but these tests must not be
counted as executed in BCApps. NAV has working API authentication and
enables those six tests separately.

Related:
[AB#650245](https://dynamicssmb2.visualstudio.com/1fcb79e7-ab07-432a-a3c6-6cf5a88ba4a5/_workitems/edit/650245),
[AB#650277](https://dynamicssmb2.visualstudio.com/1fcb79e7-ab07-432a-a3c6-6cf5a88ba4a5/_workitems/edit/650277),
[AB#625894](https://dynamicssmb2.visualstudio.com/1fcb79e7-ab07-432a-a3c6-6cf5a88ba4a5/_workitems/edit/625894).
NAV test-enablement/uptake also tracks
[AB#650246](https://dynamicssmb2.visualstudio.com/1fcb79e7-ab07-432a-a3c6-6cf5a88ba4a5/_workitems/edit/650246)
and
[AB#650247](https://dynamicssmb2.visualstudio.com/1fcb79e7-ab07-432a-a3c6-6cf5a88ba4a5/_workitems/edit/650247).

This supersedes the overlapping repair work in drafts microsoft#11451 and microsoft#11452.
Their other already-upstream changes are not replayed. The older drafts
remain open until their owners reconcile/close them after this work is
merged.

## Validation

- Static JSON/exclusion checks and `git diff --check` passed; read-only
review found no significant issue.
- Latest BCApps main was fetched and verified included:
`0c994435e3ee038dbaf66822f8a2791b1aa3f43a`.
- Expected complete BCApps Default suites on this source: 20 tests in
codeunit 148338 and 74 in codeunit 148339, including all 14 re-enabled
methods. HTTP API tests remain excluded in BCApps by explicit user
decision; their runtime evidence must come from the manually queued NAV
buddy build instead.
- Local W1 tenant2-1 resolution initially timed out because MSSQLSERVER
was stopped. After the user requested local repair, that stopped
dependency was started and both relevant databases are ONLINE. Tenant2-1
remains Failed; its Base/System/Application/Expense/Test apps are
uninstalled and Cleaned. Normal tenant synchronization reports the
tenant is not mounted. Shared NST is still 29.0.54137.0, incompatible
with a current full BaseApp30 build.
- No local publication or tests have run. No running service was
restarted, no tenant1-1 data/configuration was changed, and no version
metadata, reset, or reprovisioning was performed. Further local repair
awaits explicit approval for an isolated BC30 environment or a
shared-environment upgrade.
- API authentication uses the existing helper unchanged. PR microsoft#10085
contains a separate shared authentication-provider change; it is not
silently imported here. Until that dependency lands, BCApps API
exclusions remain identical to main. NAV buddy results must establish
whether the historical request-disappearance symptom is resolved.
- CI compile, publication, and actual per-method XML/log execution
verification are pending. A green aggregate check alone is not
sufficient: earlier CI could report success after a codeunit
runtime-compilation failure.
- Private NAV uptake draft: [NAV
#254455](https://dynamicssmb2.visualstudio.com/Dynamics%20SMB/_git/NAV/pullrequest/254455).
It removes 21 NAV method exclusions, including the six API cases, and
restores the Expense Agent Tests app to `Get-AppsToInstall` by removing
the blanket runner filter introduced in
`f09e1491f2adacca7a851a12587966daf91d993d`.
- The user will queue its buddy build manually. NAV remains draft until
BCApps merges, the pointer is updated to an actual main commit, and
buddy logs prove app installation and per-method execution. Static
runner selection is not runtime installation evidence.






Whole-app NAV test exclusion and installation/execution validation:
[AB#650370](https://dynamicssmb2.visualstudio.com/1fcb79e7-ab07-432a-a3c6-6cf5a88ba4a5/_workitems/edit/650370).
The scoped bugs 650245, 650246, 650247, 650277 and 650370 are Active
while verification is pending.


## CI iteration: 79ef58 (superseded by RU fixture correction)
Actual W1 Default JUnit artifact 10646077590 from run35596801127 records
148338 **20/20 passed** and 148339 **74/74 passed**, zero errors/skips,
including all14 re-enabled methods. DE Default JUnit also
records20/20+74/74.

RU Default job106353051317 failed: 14833820/20passed, but all74 Spend
Request tests failed during Initialize because
PrepareNormalGenPostingSetup could not find a fully populated General
Posting Setup in the UnitTest database. This is fixture initialization,
not74 different product failures.

Commit0ed0d44f92 creates a complete posting setup using existing Library
- ERM helpers before the country-specific setup. New-head validation is
pending; the prior-head W1/DE passes are not a claim that this new
commit has passed. No tests were disabled for this failure. Local and
NAV buddy execution caveats above remain.


## CI iteration: 0ed0d44 (superseded by CH VAT fixture correction)
Actual JUnit from run35616107333 attempt2 verifies **W1 and RU each
passed all20 permission tests and74 Spend Request tests**, zero
failures/errors/skips. W1 artifact10658609682; RU artifact10658544297.
This confirms the RU posting-setup correction.

CH Default job106447478820 failed: permissions20/20passed; all74 Spend
Request cases stopped in country VAT initialization because the selected
Normal VAT template referenced a nonexistent Sales VAT Account.
Artifact10659053532 and the job stack identify Library - ERM Country
Data.CreateVATPostingSetup.

Commit bd80ea3 initializes the VAT template before country setup,
creating replacement Sales/Purchase VAT accounts only when the
referenced account is missing. Valid account references and all
assertions remain unchanged; no test is disabled. Fresh validation of
W1, RU and CH on this new head is pending. Older-head pass evidence is
not a claim that the new head passed.


## Prior-head test execution: bd80ea3
Downloaded actual JUnit artifacts from run35644720549 attempt2 and
verified every required re-enabled method, not just the job conclusion:

| Country | CU148338 Expense Permissions | CU148339 Spend Request |
Artifact |
| --- | --- | --- | --- |
| W1 | 20/20 passed | 74/74 passed | 10668715386 |
| RU | 20/20 passed | 74/74 passed | 10667802737 |
| CH | 20/20 passed | 74/74 passed | 10668516148 |

All three have zero failures, errors and skipped cases in these suites.
All14 re-enabled role/posted-history/page-action cases executed. This
verifies both country fixture corrections and placement in the
Default/UnitTest lane. It does not establish fully test-owned VAT setup:
the current helper repairs the selected existing VAT template when
necessary.

Run35644720549 attempt2 completed with160 successful jobs,2 skipped and2
failed (BE Uncategorized plus the aggregate status check). The
status-check log names ONLY the BE platform/indexes/platform.json
download/setup failure; no Expense test failure remains in the verified
W1/RU/CH suites. The overall CI gate is therefore still red. No rerun
was initiated by this agent. HTTP API tests remain intentionally
excluded in BCApps; current NAV buddy and local runtime validation are
not claimed. The user-supplied older NAV buddy3641608 did install
Expense Agent and its test app and pass20 permission tests, but all74
Spend Request cases hit the pre-fix RU initialization failure; its queue
timestamp preceded the RU correction.


## Current fixture repair: 2d45e6f
The supplied NAV buddy3641753 AU log passed all20 permission tests but
failed all74 Spend Request tests in
UpdateZeroVATPercentInVATPostingSetup: the demo-data helper assumed an
existing blank-business-group VAT row. Earlier BCApps AU also
passed94/94 on bd80ea3; that baseline difference does not prove the
fixtures are independent.

Replace broad demo-data normalization rather than adding another
country-specific fallback:
- Create fresh Expense Posting Groups and their G/L accounts, fresh
Employee Posting Groups with valid expense accounts, and fresh payment
methods. Bind the report fixtures to these records instead of reusing
arbitrary posting masters.
- Remove the unrelated country VAT/general/purchase setup mutations and
the earlier RU/CH template repairs. These Spend Request lifecycle
fixtures use no-VAT expense accounts; retain the explicit country helper
for Journal Templ. Name Mandatory=false.
- Restore General Ledger, Human Resources, Source Code and Expense Agent
singleton setup between tests with Library - Setup Storage. Retain
existing scoped Expense cleanup; do not delete unrelated VAT or ledger
masters.
- Preserve all74 test methods, assertions, scenario/feature tags and
handlers. No exclusions or production behavior changed.

Validation: static call-site checks and git diff --check passed. Fresh
local resolution now reports tenant2-1 Operational, but a dedicated
tenant2-1 AL MCP download returned404 for System30.0.0.0 (No published
package matches the provided arguments). Application symbols downloaded
to the worktree/tenant cache; required symbols remain incomplete. No
local compile/publication/test was performed, and no shared symbols,
metadata changes, reset, service restart or tenant1-1 modification was
used. Fresh CI and manually queued NAV buddy execution are pending; all
bd80ea3 pass evidence above is prior-head only.

Pipeline audit: both NAV and BCApps AU UnitTest setup use an empty
company, not Contoso generation. BCApps can retain the Disabled runner
across ordinary app passes; the exact origin of the differing AU VAT
data is unproven. Open PR microsoft#10085 has overlapping
clean-tenant/split-isolation remediation. No shared-runner changes are
imported into this fixture PR.


## Warning-gate correction: 67d0e3c
Run35714820873 on2d45e6f finished failed. RU Default and SE/IT Clean
logs identify two new AA0198 warnings: the new global
LibraryHumanResource shadowed two existing local declarations in
SpendRequestTest. RU stopped at the compilation/new-warning gate before
publication and tests; this was introduced by the fixture change, not
infrastructure.

Commit67d0e3c removes exactly those two redundant local declarations and
reuses the global instance. All74 test bodies/assertions are unchanged;
exact two-line diff and diff checks passed. Fresh CI compile/publication
and actual W1/RU/CH/AU94-test execution remain pending. Monitoring
resumes every30minutes; no buddy build or CI rerun is automatically
queued, and local tenant-specific System30 symbols remain unavailable.


## Payment-method fixture correction: 87357b7
The67d0e3c app builds passed for W1/RU/CH/AU, clearing AA0198. Actual AT
Default JUnit artifact10705006253 from run35730199203 records
CU14833820/20passed and CU14833955/74passed,19failed. All19 failures are
the same fixture defect: Expense Payment Method enforces uniqueness by
nonblank Reimbursement Type, so creating a new Employee Paid method for
each report collides with the prior method. This is not a product
assertion failure.

Commit87357b7 clears only Employee Paid/Company Paid payment-method
fixtures in Initialize, after Expense transaction cleanup and before the
initialized guard. The six factories use the existing find-or-create
library helper: the first call creates this test's method, and further
calls reuse it without violating uniqueness. Posting-account ownership
and all74 scenarios/assertions/tags/handlers remain unchanged. Static
checks verify every-test cleanup ordering, all six callers, preserved
assertions and no HR-library shadowing; runtime verification on this new
head is pending.

The earlier run also has an independent LegacyTestsBucket1
container-setup failure downloading platform/indexes/platform.json
(HTTPS connection timeout). No automatic retry or
shared-runner/environment change is included. Local tenant-specific
System30 symbols remain unavailable; latest NAV buddy execution remains
unverified.


## Verified current-head runtime: 87357b7
Downloaded actual JUnit from run35751572706 attempt1 and checked
complete suite counts, zero failures/errors/skips and every required
re-enabled method:

| Country | CU148338 Permissions | CU148339 Spend Request | Artifact |
| --- | --- | --- | --- |
| W1 | 20/20 passed | 74/74 passed | 10714234115 |
| RU | 20/20 passed | 74/74 passed | 10714194977 |
| CH | 20/20 passed | 74/74 passed | 10715030599 |
| AU | 20/20 passed | 74/74 passed | 10714392965 |
| AT | 20/20 passed | 74/74 passed | 10713924969 |

All14 re-enabled methods executed in each country. This verifies the
latest payment-method cleanup/reuse correction, including the AT
regression. All five country app builds passed. W1 job106867710487
additionally records publication, synchronization and installation of
both Expense Agent (Preview) and Expense Agent
Tests30.0.2147483647.85851, followed by successful execution of both
codeunits.

The overall workflow is not green: it is still running, with US
LegacyTestsBucket2 job106867713372 failed because its self-hosted runner
lost communication with GitHub. That infrastructure failure is separate
from the verified target suites; no automatic rerun was requested.

NAV draft254455 remote commit e939957a13d896b18ae1bf053a14ab6949a052fd
already consumes this exact87357b7 commit. Fresh NAV buddy verification
remains necessary, especially Codeunit isolation and the six NAV-enabled
HTTP API tests that remain excluded in BCApps. The supplied older
NAV3642277 W1 log references67d0e3c and reproduces the now-corrected19
payment-method failures; it does not test87357b7. No current NAV/local
runtime pass is claimed.


## Final BCApps CI gate
Run35751572706 subsequently completed SUCCESS on attempt2 for the
same87357b7 head:162 successful jobs,2 skipped,0 failed. The earlier US
legacy-runner communication failure is cleared. The agent did not
request this retry. Five-country actual20+74 execution evidence above
remains valid for this exact source commit. NAV validation remains
separate.


## NAV HTTP API follow-up: af10e62 (validation pending)
The supplied NAV3642786 NL IntegrationTests log (build30.0.54998.2786)
executes all15 CU148347 cases:7pass,8fail. These HTTP API cases remain
intentionally excluded in BCApps, so the prior87357b7 unit-test/green-CI
evidence does not validate them.

Library - Graph Mgt. appends successful responses to the supplied
ResponseText and raises failed requests before populating that output.
The failures expose two test-harness defects: stale concatenated
responses explain the missing traveler expansion and two
foreign-currency assertions; parsing empty response JSON explains four
negative-case failures. This test-only commit clears all32 HTTP response
buffers and checks failed requests through the helper's raised error,
preserving expected HTTP400/ALDialog, domain/owner/request-number
details, the server BadRequest read-only-status guard, and persistence
checks. All15 methods, existing tags and conditional compilation remain
unchanged.

The eighth failure is still under investigation: the dates case fails
the first local GetBySystemId immediately after successful POST, before
PATCH. The test now explicitly compares the returned id with the
client-supplied id before the existing persistence check, so a future
failure can distinguish rewritten/ignored identity from record
disappearance. The supplied-GUID requirement is NOT removed and no
production workaround is applied.

Static diff/buffer/case checks pass. A fresh dedicated tenant2-1 symbol
download retrieved5of6 requested dependencies but again failed404 for
System30.0.0.0; no local compile, publish or tests ran. Fresh CI
compilation is pending and cannot substitute for NAV API execution while
BCApps exclusions remain. Another NAV buddy build has not been queued
automatically; the prior queue authorization was used for2773217. Both
drafts remain in-progress, not fully validated.



Current follow-up head: ff267e3. The
returned-identity diagnostic uses the existing AL Evaluate(Guid,
JsonValue.AsText()) pattern. This supersedes af10e62; its identity
investigation and runtime-validation caveats still apply. No additional
NAV build has been queued.




## ff267 CI gate completed
Run35869253473 attempt1 completed SUCCESS on
ff267e3:162 successful jobs,2 skipped,0
failed. Actual W1 and RU build logs confirm Expense Agent Tests
compiled, with unchanged warning baselines (40304 W1;42672 RU). CU148347
HTTP API cases remain excluded in BCApps: this verifies compilation and
the CI gate, NOT the eight NAV API failures or the unresolved date POST
identity. Local runtime validation remains pending; no NAV rerun was
initiated by this monitor.



## Locally verified API persistence fix: 29d7bb5
The remaining two API failures were reproduced outside the test runner:
user-scoped owner/date-only POST returned201 but no stored request
(blank number; subsequent GET returned0). Adding purpose caused
insertion, but the tests were NOT weakened with such a payload
workaround.

Fix page7134 instead: copy supplied date values onto Rec to register a
real record change while retaining deferred paired validation; clear the
route-prefilled owner on new records and default it at insertion only
when requestedBy was omitted. Explicit supplied owners still undergo
scope validation. Requested identity and all existing
date/ownership/persistence assertions are retained.

Local validation after the explicitly authorized BC30 W1 reset (agents
enabled, two tenants), exclusively on tenant2-1:
- Downloaded fresh tenant-specific symbols; built and published both
Expense Agent (Preview) and Expense Agent Tests30.0.0.0 through a
dedicated AL MCP host.
- CU148347: all15 HTTP API tests PASSED,0failures/0skips, runner130451
(required isolation Disabled), CRONUS W1, password-only test
administrator. Includes complete date-only PATCH sequence and both
original missing-record cases. Evidence:api-local-insert-fix.xml.
- Empty Company regression: CU14833820/20 andCU14833974/74
PASSED,0failures/0skips, runner130450 Codeunit isolation.
Evidence:local-unit-regression-20260924.xml. The helper's 'Disabled'
setup log describes code-coverage tracking, not isolation.
- Additional direct HTTP checks passed: supplied-id/date-only POST
persists; omitted owner defaults from route and persists; explicit blank
owner and unscoped missing owner return400 without inserting.

Local runtime builds use CodeCop/UICop with default severities; partner
AppSourceCop defaults incorrectly reject first-party namespaces/IDs and
the full repository ruleset promotes pre-existing obsolete/style
warnings. No source warnings were suppressed or manifests altered; CI
remains the full first-party compilation gate. Fresh current-head CI and
NAV buddy results are still pending.

BCApps HTTP API exclusions remain unchanged pending the separate
authentication prerequisite; NAV keeps these APIs enabled. The
Windows-linked local account was unsuitable for the existing Basic-auth
helper, so a password-only test account was used on tenant2-1. No
production authentication behavior was changed. Canonical reset-tool
compatibility fixes remain local and are not included in this PR.


## Final merged-source local verification: aaa5a76
Merged current BCApps main (a18b1b3) normally to resolve the sole
namespace-import conflict, retaining both imports and all upstream
changes. Main contributes six additional Spend Request tests, bringing
CU148339 to80; no scenarios were removed.

Rebuilt and published Expense Agent and its tests from the merged
source. The seed Base Application lacked the newly inherited
Purpose-validation behavior, so the matching unmodified Base
Application30.0.0.0 was built from the same source and published only to
tenant2-1 (verified tenant scope). No BaseApp source workaround or
version/metadata override was used.

Final persisted local results on tenant2-1: **15/15 HTTP API +20/20
Expense Permissions +80/80 Spend Request =115/115 passed**, zero
failures/skips. HTTP runner130451 in CRONUS W1; unit runner130450 in
Empty Company. Reports:api-local-final-main.xml
andlocal-unit-final-main.xml. The original date/owner POST payloads and
persistence assertions pass without adding purpose. Source worktree is
clean; compiler-generated report-layout edits were not committed.

This supersedes the earlier unresolved-identity caveat. New-head CI and
NAV buddy results remain pending; BCApps API exclusions and NAV API
enablement policy are unchanged.


## W1 Bucket5 fixture follow-up: 40a64b5
The supplied NAV3644685 log reports4,814passed/2failed:
CU139194.CDSConnectionWizardCheckModifyCDSConnectionURL rejects a
positive fixture outside dynamics.com; CU139148.NotExpiredToken fails
its expiry assertion. These are separate from the repaired Expense APIs.

Test-only corrections: use valid dynamics.com hosts for positive HTTPS
normalization cases, preserve explicit-port/path expectations and HTTP
rejection, and exercise SaaS validation with environment restoration.
JWT fixtures now use the public Unix Timestamp helper rather than manual
timezone/epoch arithmetic, with a one-hour past/future margin instead of
one second. Production URL/security and JWT-expiry implementations are
unchanged; no further tests are disabled.

Both test apps compile locally through AL MCP with tenant2-1 symbols.
The corrected CDS case passes locally. Full local validation is
incomplete: the CRM suite has pre-existing local
AutoRollback/EmailLogging and on-premises-mode setup failures; the
latter reproduces independently of the modified case. Tests-Misc server
publication rejects its existing MockAzureKeyVaultSecretProvider
reference despite successful local compilation. The missing standard
MockTest add-in was restored, but no service restart or validation
bypass was performed. Token runtime and full-suite verification must
come from the buddy build or follow-up local runtime maintenance. No
full-pass claim is made for these two codeunits.

The prior115 local Expense API/permission/Spend passes remain evidence
for unchanged Expense code, not proof of these new fixture repairs.
Existing NAV retention/VIES quarantines and differing BCApps/NAV API
policies remain unchanged.

## Assisted-setup fixture follow-up: c52631a
After ADO2787333 failed, the matching WorkIQ email for NAV3644810
identified two RU Bucket5 failures in CU139196:
RunAssistedSetupFromNormalSetupRecordMissing and
RunAssistedSetupFromNormalSetupRecordExists. Both used TEST as a
positive Server Address and hit the dynamics.com host guard.

Only those two fixture URLs become https://test.dynamics.com, with
corresponding comments updated. The existing wizard-propagation
assertions, handlers, test list and production validation remain
unchanged; no additional exclusions were added.

The CRM test app compiled and published on tenant2-1. Local runtime
verification is blocked before these assertions: unchanged Initialize
calls DisableEncryption, which is unsupported in this agent-enabled
environment (47 reported,4 passed,43 failed in setup). No
encryption/credential/service changes or assertion bypass were
performed. NAV buddy execution is the remaining validation route; these
two cases are not yet claimed passing.



## Scope correction: 5de4cb7
At the user's explicit request, this BCApps PR is limited to Expense
Agent and Spend Request changes. Our earlier changes to
CDSConnectionWizardTests, CDSConnectionSetupTest and UTREST have been
restored exactly to their pre-repair aaa5 contents. The final PR diff
contains only four Expense Agent AL files and its disabled-test
manifest; the historical non-Expense fixture proposals above are
superseded and NOT included.

NAV handles unrelated failures through exact-method temporary exclusions
instead: the four confirmed Bucket5 methods (one CDS wizard URL case,
two CDS assisted-setup cases and UT REST.NotExpiredToken), alongside the
previously authorized four Retention Policy and ten VIES methods. These
are quarantines, not fixes or passing tests; bug filing remains
deferred. All other existing exclusions are preserved.

BCApps keeps the Expense non-API re-enables and its HTTP API exclusions.
NAV retains the Expense app re-enable and its21 method re-enables,
including the six HTTP API cases. The prior
local15API+20permissions+80Spend passes apply to unchanged Expense code;
fresh CI/buddy results remain pending. Future repairs in this BCApps PR
must not modify unrelated tests.

---------

Copilot-Session: 988fb581-008c-4e0d-99c1-285cd45d49e7

This branch was successfully deployed

1 active deployment
triage — 4a76bb71 Deployed Sep 29, 2026 by t-prda via Classify team ownership #6167
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ExpenseManagement Team: Integrations GitHub request for Integrations area

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants