feat: encode the PII script capability in the CgScript file name - #159
Merged
Merged
Conversation
Parses name[@<userId>[.pii][.public]].cgs from the leaf only; canonical .pii-then-.public order; ids 0..2147483647; fail-loud errors naming the file, the offending suffix and the expected shape.
Grammar, valid and rejected shapes, the four accepted behaviour changes including the one-time rename, the site PII policy predicate, and that the deployer still requests only scriptdeployment:w.
Default interface member is fail-closed (false) so custom providers keep compiling; ScriptFromFileOnDisk now delegates the whole filename grammar to ScriptFileNameParser; the directory provider reports duplicate script identities with both file names instead of a raw dictionary error.
…med names The analyzer source-links ScriptFileNameParser and passes the leaf with its .cgs extension, so wrapper names always match what the deployer registers. Malformed names now fail the build with CGS028 (Error) instead of silently emitting a wrapper for a wrong script name that would never exist on the site. Accepted naming breaks shipped with this change, documented in the README: - a malformed tail after the last @ is an error where it used to be folded into the script name (Name@123.publc.cgs, Name@abc.cgs, Name@123.public.pii.cgs); - a trailing .pii/.public with no @ is an error (Name.pii.cgs, Name.public.cgs); - .pii/.public combined with @0 is an error; such a file used to register and then fail on the site with 412/403; - an existing Name@123.pii.cgs now registers as script 'Name' instead of the literal 'Name@123.pii' - a one-time rename; the deployer reports a duplicate script identity naming both files if Name.cgs also exists.
The deployer now forwards the PII classification parsed from the file name to the site. The token request still asks only for scriptdeployment:w: the site infers the capability from that scope, and its deploy gate checks the impersonated user instead of a pii scope. Capture-handler tests assert the raw request bodies, the call order, and the zero-request failure path for a malformed file name.
The previous wording implied @-containing names keep deploying; they do not. Also adds the README example Report@123.publc.cgs as a literal test row so the documented examples and the test data agree in both directions. Plan: .omo/plans/cgscript-pii-filename-marker.md
The rule row belongs in AnalyzerReleases.Shipped.md with the other shipped rules; Unshipped keeps its empty table. The README section shrinks to the grammar line, what the markers mean, the fail-loud behaviour and the pointer to the ScriptFromFileOnDisk documentation, which holds the details. The skill template keeps the two marker rows without the added rules paragraph.
Development-run scripts treat .pii and .public as ordinary names; the sentence states the rule without referring to past behaviour, keeping the security section terse.
This comment has been minimized.
This comment has been minimized.
The new test project now emits coverlet cobertura like the LSP test project, into its own subdirectory of test-results-output: both projects used coverlet default file name in the same directory, so a solution-wide run (what CI does) silently kept only one report. The workflow glob is recursive, so both reports now reach ReportGenerator.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
feat: encode the PII script capability in the CgScript file name
What this does
A
.cgsfile can declare that it may read personal data, in its own file name, using the same metadata channel that already carries impersonation and public access:The deployer parses that marker with one shared strict parser and sends it to the site as
canAccessPIIin the existingUpdateScriptspayload - a field the site already models (QuestionnaireScript.CanAccessPII), enforces (IPiiAccessPolicy.CanIssueAuthenticationPii) and hashes.Valid:
Name.cgs,Name@0.cgs,Name@123.cgs,Name@123.pii.cgs,Name@123.public.cgs,Name@123.pii.public.cgs..piisits closest to the id it scopes;.publicis the outer modifier.Why
The file name was already the only channel that carried a script's security metadata, and the site contract already had the field - nothing on the file side could express it. This closes that gap without adding a configuration surface.
Accepted behaviour changes
Fail-loud replaces silent name-folding, so these shapes are now errors naming the file and the offending suffix: unknown token, wrong marker order (
.public.pii), duplicate markers, empty token, non-numeric / negative / out-of-range ids (max2147483647- the site casts toint), a marker combined with@0, a.pii/.publictail with no@, a leaf without.cgs, and control characters or"in a name.Consequently: any
@in the leaf is a metadata boundary, so e.g.user@domain.cgsmust be renamed; andName@123.pii.cgsnow registers as scriptNameinstead of the literalName@123.pii- a one-time rename, with a duplicate-identity error naming both files ifName.cgsalso exists.These are enumerated in the generator commit message so the generated release note carries them; the README stays terse and points at the
ScriptFromFileOnDiskdocumentation for the grammar details.No extra permission on the deployer side
The token request is unchanged (
scope=scriptdeployment:w, asserted by the payload tests). A site that predatescanAccessPIIsilently ignores the member, so deploy the site first; the impersonated user must satisfy the site's workflow-PII policy (TemplateEligible && !BuiltInAdmin && !AdminGroup).Analyzer consumers
CGS028(Error) makes a malformed script file name fail the build instead of emitting a wrapper that calls a script name the deployer would never register. The rule is tracked inAnalyzerReleases.Shipped.mdalongside the other shipped rules.Verification
Catglobe.CgScript.Deployment.Tests(net10.0/xunit): 81 passed / 0 failed / 0 skipped - the filename truth table (62 rows), provider identity rules, the capturedUpdateScriptsbodies, and a Roslyn-driven generator parity test.Catglobe.CgScript.EditorSupport.Lsp.Tests344 passed / 0 failed / 0 skipped.@115.publicscript still generates the same wrapper; a realAddCgScriptDeploymentend-to-end run against a local stub endpoint captured"canAccessPII":truefor a.piiscript with nopiiscope on the token request; a real MSBuild run withEmitCompilerGeneratedFilesemittedExecute("Live", ...)forLive@7.pii.cgs.RS2007warnings.Plan:
.omo/plans/cgscript-pii-filename-marker.md