bcquality/microsoft/knowledge/security/secretstrsubstno-for-composing-secrets.md
Jesper Schulz-Wedde a9f3c50863 Regenerate microsoft/knowledge from upstream BCApps instructions
The previous LLM-generated knowledge files contained factual
hallucinations. The most visible was the claim that `FindFirst` /
`FindLast` "forces a full-table scan" on an unfiltered record - it does
not; those APIs return a single row via the current key.

Other inaccuracies the audit found and fixed:

* `FindSet(true)` was described as "taking a LockTable". The correct
  upstream phrasing is that `FindSet(true)` sets
  `ReadIsolation::UpdLock` on the read. UpdLock and LockTable are
  related but distinct mechanisms.
* The list of production-scale tables had been invented beyond the
  upstream source (e.g. "Detailed Cust. Ledg. Entry") without a
  citation. The regenerated list matches the ten tables upstream lists
  with their P95 row counts.
* `SetLoadFields` guidance had been augmented with an extra mechanism
  claim ("the database resolves the filter using the index without
  hydrating the value") not present in upstream.

Approach: full regeneration of `microsoft/knowledge/` from the six
upstream BCApps Code Review instruction files, with Microsoft Learn /
the AL language reference as a secondary source. Every claim in every
regenerated file is anchored to a verbatim upstream quote (or a Learn
URL); the audit trail lives in artifacts/trace-<domain>.json on the
session workspace.

The PR #11 transaction/error-handling cluster is preserved verbatim:

* performance/understand-implicit-transaction-boundary.md
* performance/codeunit-run-as-atomic-sub-operation.{md,good.al,bad.al}
* performance/codeunit-run-requires-prior-commit-inside-transaction.{md,good.al,bad.al}
* performance/use-tryfunction-for-error-catching-not-rollback.{md,good.al,bad.al}
* performance/avoid-commit-inside-loops.{md,good.al,bad.al}
* security/commitbehavior-attribute-scopes-explicit-commits.{md,good.al,bad.al}
* testing/transactionmodel-attribute-governs-test-transactions.{md,good.al,bad.al}

These articles already cite Microsoft Learn and were carefully
cross-referenced; the regeneration skips their topics rather than
duplicating them.

File counts after regeneration:

  performance   35 .md  (5 preserved + 30 new)
  privacy       17 .md
  security      18 .md  (1 preserved + 17 new)
  style         33 .md
  testing        1 .md  (preserved)
  ui            19 .md
  upgrade       18 .md

Total 141 atomic knowledge files, each strictly one rule. All pass
.github/scripts/validate_frontmatter.py with 0 errors and 0 warnings.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-21 09:53:09 +02:00

1.6 KiB

bc-version domain keywords technologies countries application-area
all
security
secretstrsubstno
secrettext
strsubstno
format
compose
al
w1
all

Use SecretStrSubstNo to compose strings that contain secrets

Description

SecretStrSubstNo is the secret-preserving counterpart of StrSubstNo. It accepts a format string and arguments (any of which may be SecretText) and returns a SecretText — the substitution happens without ever materializing the result as plain Text. It is the right tool whenever a secret needs to be embedded in a larger string: an Authorization: Bearer <token> header value, a URI that includes an API key as a query parameter, or any other interpolation that combines a SecretText with surrounding context.

Best Practice

Compose every secret-bearing string through SecretStrSubstNo and keep the result as SecretText end-to-end. Pass the result to the SecretText overload of the consumer — HttpClient.SetSecretRequestUri, HttpHeaders.Add, or HttpContent.WriteFrom. See sample: secretstrsubstno-for-composing-secrets.good.al.

Anti Pattern

Calling StrSubstNo('Bearer %1', Token.Unwrap()) to build the header value, or concatenating 'Bearer ' + Token.Unwrap(). Both produce a plain Text containing the secret, which is then visible in the debugger and in any subsequent log or trace. Reviewers should flag any Unwrap() whose result is fed into StrSubstNo or used in + concatenation — SecretStrSubstNo removes the need for either. See sample: secretstrsubstno-for-composing-secrets.bad.al.