mirror of
https://github.com/microsoft/BCQuality.git
synced 2026-08-06 17:36:53 +01:00
Extract 55 knowledge articles from BC review-agent prompt
Adds 55 articles (plus 76 code samples) spanning four new domains and two existing domains, extracted from the internal Business Central review-agent prompt. Content was filtered against BCQuality's remedial-knowledge premise: each article encodes BC-specific behaviour, a CodeCop rule, a platform API semantic, or an anti-false-positive guideline that a capable LLM would otherwise get wrong. New domains: - privacy (11 articles): DataClassification inheritance semantics, the StrSubstNo-defeats-Error-telemetry-classification pitfall, Privacy Notice consent for outgoing requests, anti-false-positives for pages and in-memory data. - upgrade (11 articles): upgrade-codeunit structure, upgrade-tag lifecycle and registration, protected DB reads, DataTransfer for large datasets, InitValue semantics, enum-ordinal preservation, obsolete-workflow, first-install detection. - ui (9 articles): caption capitalization by phrase type, tooltip voice, teaching-tip vs tooltip, tour-tip conventions, character limits, banned terms, ampersand handling, title punctuation. - style (11 articles): label-suffix convention, API page naming, temporary-variable prefix, label properties (Comment/Locked), named invocations, FieldCaption in user messages, OptionCaption pairing, Error-parameter passing, `this` keyword, required parentheses, file naming. Gaps in existing domains: - performance (11 articles): production-scale table catalog (no row counts, per internal-data concern), anti-false-positive for bounded tables, guard-before-Get ordering, redundant-Get-in-OnAfterGetRecord, LockTable in read-only helpers, combined ModifyAll passes, writes in OnAfterGetRecord, SetLoadFields heuristics, temporary-table regressions, FlowField source-table widening, MaintainSQLIndex disabling SIFT. - security (2 articles): environment-specific hardcoded GUIDs, ValidateTableRelation=false on user input. Intentionally excluded: specific production P95 row-count numbers (aggregated internal telemetry); rewritten as categorical guidance on which tables to treat as production-scale without publishing sizes. All articles use `bc-version: [all]` (applies to every BC version, per the new schema sentinel). Validator passes with 0 errors / 0 warnings.
This commit is contained in:
parent
9a4198eb28
commit
e570d6113f
131 changed files with 2799 additions and 0 deletions
|
|
@ -0,0 +1,16 @@
|
|||
tableextension 51303 "Sec Sample VTR Bad" extends "Sales Header"
|
||||
{
|
||||
fields
|
||||
{
|
||||
// Editable user input with validation suppressed and no fallback check.
|
||||
// The user can type any string; downstream Get against Customer will fail
|
||||
// or return a wrong row.
|
||||
field(50102; "Customer No."; Code[20])
|
||||
{
|
||||
Caption = 'Customer no.';
|
||||
DataClassification = CustomerContent;
|
||||
TableRelation = Customer."No.";
|
||||
ValidateTableRelation = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
tableextension 51302 "Sec Sample VTR Good" extends "Sales Header"
|
||||
{
|
||||
fields
|
||||
{
|
||||
// User-editable field keeps ValidateTableRelation default (true).
|
||||
field(50100; "External Customer Ref"; Code[50])
|
||||
{
|
||||
Caption = 'External customer reference';
|
||||
DataClassification = CustomerContent;
|
||||
TableRelation = Customer."No.";
|
||||
}
|
||||
|
||||
// System-controlled field: validation bypass is acceptable because
|
||||
// the value is populated by controlled upstream code, not the user.
|
||||
field(50101; "System Batch Id"; Code[20])
|
||||
{
|
||||
Caption = 'System batch ID';
|
||||
DataClassification = SystemMetadata;
|
||||
TableRelation = "Job Queue Entry".ID;
|
||||
ValidateTableRelation = false;
|
||||
Editable = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
---
|
||||
bc-version: [all]
|
||||
domain: security
|
||||
keywords: [validatetablerelation, user-input, lookup, integrity, validation]
|
||||
technologies: [al]
|
||||
countries: [w1]
|
||||
application-area: [all]
|
||||
---
|
||||
|
||||
# Do not set ValidateTableRelation = false on fields that accept user input
|
||||
|
||||
## Description
|
||||
|
||||
`TableRelation` on a field tells the platform that the value must exist as a primary key in the related table. `ValidateTableRelation = false` suppresses that check at validation time. On system-populated fields — values the code sets from a controlled source and never displays as editable — the suppression is acceptable because the integrity guarantee comes from the upstream writer. On a field the user types into (a page field, an import column, an API payload), disabling the validation means any value at all can be written: a non-existent customer number, a typo, a deliberate bad value. The table no longer enforces the relation, and downstream code that Gets the related row with an unguarded lookup breaks.
|
||||
|
||||
## Best Practice
|
||||
|
||||
Leave `ValidateTableRelation = true` (the default) on any field the user can set. When the default would produce unhelpful behaviour — a transient lookup that does not yet exist at validation time, a reference that uses a non-primary-key column — handle it with a targeted OnValidate trigger that performs the semantic check explicitly. Use `ValidateTableRelation = false` only when the field is genuinely system-controlled and the writer has already validated the reference.
|
||||
|
||||
See sample: `do-not-disable-validatetablerelation-on-user-input.good.al`.
|
||||
|
||||
## Anti Pattern
|
||||
|
||||
A `Customer No.` field on an editable page with `TableRelation = Customer."No."` and `ValidateTableRelation = false` and no OnValidate fallback. The user can type any string; the platform accepts it; a later Get against Customer fails or returns the wrong row.
|
||||
|
||||
See sample: `do-not-disable-validatetablerelation-on-user-input.bad.al`.
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
codeunit 51301 "Sec Sample EnvGuid Bad"
|
||||
{
|
||||
procedure GetTenantId(): Text
|
||||
begin
|
||||
// Tenant GUID hardcoded. Extension works in one environment, fails in every other.
|
||||
exit('{12345678-1234-1234-1234-123456789012}');
|
||||
end;
|
||||
|
||||
procedure GetAadApplicationId(): Text
|
||||
begin
|
||||
// AAD application GUID hardcoded. Same problem, surfaces as an authentication error.
|
||||
exit('{87654321-4321-4321-4321-210987654321}');
|
||||
end;
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
codeunit 51300 "Sec Sample EnvGuid Good"
|
||||
{
|
||||
procedure KnownSystemId(): Guid
|
||||
begin
|
||||
// Stable across tenants and versions — Base Application Id.
|
||||
exit('{437dbf0e-84ff-417a-965d-ed2bb9650972}');
|
||||
end;
|
||||
|
||||
procedure GetTenantId(): Text
|
||||
var
|
||||
EnvironmentInformation: Codeunit "Environment Information";
|
||||
begin
|
||||
// Environment-specific values are retrieved at runtime.
|
||||
exit(EnvironmentInformation.GetTenantId());
|
||||
end;
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
---
|
||||
bc-version: [all]
|
||||
domain: security
|
||||
keywords: [guid, tenant-id, aad, environment, hardcoded]
|
||||
technologies: [al]
|
||||
countries: [w1]
|
||||
application-area: [all]
|
||||
---
|
||||
|
||||
# Hardcoded GUIDs are only safe for well-known system identifiers
|
||||
|
||||
## Description
|
||||
|
||||
AL code sometimes carries hardcoded GUIDs. Some are platform-defined, stable across tenants and versions, and legitimately constant — the Base Application's ApplicationId (`{437dbf0e-84ff-417a-965d-ed2bb9650972}`) is the canonical example. Others identify a specific tenant, a specific Azure Active Directory application, or a specific environment; these look identical at the source-code level but are environment-bound and break the moment the extension is deployed anywhere else. Shipping an environment-specific GUID as a constant effectively locks the extension to one environment, and the failure mode in other tenants is usually an authentication error with no code-level signal pointing at the literal.
|
||||
|
||||
## Best Practice
|
||||
|
||||
Hardcoded GUIDs are acceptable for well-known system identifiers that are stable across environments — document the identifier with a comment that names what it refers to. For tenant IDs, AAD application IDs, API subscription IDs, and any value that varies by deployment, retrieve at runtime from IsolatedStorage, configuration tables, or the platform APIs that expose the current tenant context.
|
||||
|
||||
See sample: `do-not-hardcode-environment-specific-guids.good.al`.
|
||||
|
||||
## Anti Pattern
|
||||
|
||||
`TenantId := '{12345678-1234-1234-1234-123456789012}';` or `AadApplicationId := '{87654321-...}';` inline in a codeunit. The extension authenticates in one environment and fails in every other; debugging starts from an AAD error message that does not mention the literal.
|
||||
|
||||
See sample: `do-not-hardcode-environment-specific-guids.bad.al`.
|
||||
Loading…
Add table
Add a link
Reference in a new issue