@decantr/verifier 1.0.3 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +104 -12
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1218,7 +1218,7 @@ function isAnonymousEntryLikeRoute(route) {
|
|
|
1218
1218
|
return route === "/" || /(?:^|\/)(?:auth|login|log-in|signin|sign-in|signup|sign-up|register)(?:\/|$)/i.test(route);
|
|
1219
1219
|
}
|
|
1220
1220
|
function isProtectedLikeRoute(route) {
|
|
1221
|
-
return /(?:^|\/)(?:app|dashboard|workspace|settings|billing|account|profile|admin|agents?|marketplace|transparency|logs?|metrics|config|console|studio|pipelines?|projects?|monitoring|overview)(?:\/|$)/i.test(
|
|
1221
|
+
return /(?:^|\/)(?:app|dashboard|workspace|settings|billing|account|profile|admin|agents?|marketplace|browse|search|listings?|seller|buyer|bookings?|favorites|messages?|orders?|checkout|cart|transparency|logs?|metrics|config|console|studio|pipelines?|projects?|monitoring|overview)(?:\/|$)/i.test(
|
|
1222
1222
|
route
|
|
1223
1223
|
);
|
|
1224
1224
|
}
|
|
@@ -1378,7 +1378,7 @@ function appendTopologyFindings(findings, essence, reviewPack) {
|
|
|
1378
1378
|
evidence: [
|
|
1379
1379
|
"Protected app surfaces need explicit routes so post-auth entry points are unambiguous."
|
|
1380
1380
|
],
|
|
1381
|
-
suggestedFix: "Add explicit primary routes such as `/dashboard
|
|
1381
|
+
suggestedFix: "Add explicit primary routes such as `/dashboard`, `/app`, `/browse`, or `/listings` for the authenticated experience."
|
|
1382
1382
|
})
|
|
1383
1383
|
);
|
|
1384
1384
|
}
|
|
@@ -1414,7 +1414,7 @@ function appendTopologyFindings(findings, essence, reviewPack) {
|
|
|
1414
1414
|
severity: "warn",
|
|
1415
1415
|
message: "Primary routes only expose auth-like destinations and do not appear to include a post-auth application surface.",
|
|
1416
1416
|
evidence: [`Primary routes: ${topology.primaryRoutes.join(", ")}`],
|
|
1417
|
-
suggestedFix: "Keep login and registration routes in the gateway section, and add at least one primary app route such as `/dashboard`, `/workspace`, or `/
|
|
1417
|
+
suggestedFix: "Keep login and registration routes in the gateway section, and add at least one primary app route such as `/dashboard`, `/workspace`, `/app`, `/browse`, or `/listings`."
|
|
1418
1418
|
})
|
|
1419
1419
|
);
|
|
1420
1420
|
}
|
|
@@ -1426,7 +1426,7 @@ function appendTopologyFindings(findings, essence, reviewPack) {
|
|
|
1426
1426
|
severity: "warn",
|
|
1427
1427
|
message: "Primary routes do not appear to include a clear post-auth application destination.",
|
|
1428
1428
|
evidence: [`Primary routes: ${topology.primaryRoutes.join(", ")}`],
|
|
1429
|
-
suggestedFix: "Use at least one primary route like `/dashboard`, `/workspace`, `/settings`, or `/
|
|
1429
|
+
suggestedFix: "Use at least one primary route like `/dashboard`, `/workspace`, `/settings`, `/app`, `/browse`, or `/listings` so the authenticated surface is explicit."
|
|
1430
1430
|
})
|
|
1431
1431
|
);
|
|
1432
1432
|
}
|
|
@@ -2022,13 +2022,13 @@ function appendSourceAuditFindings(findings, sourceAudit, essence, reviewPack) {
|
|
|
2022
2022
|
id: "source-inline-styles-present",
|
|
2023
2023
|
category: "Source Audit",
|
|
2024
2024
|
severity: "warn",
|
|
2025
|
-
message: "Source files still contain inline style attributes, which undermines the compiled treatment contract.",
|
|
2025
|
+
message: "Source files still contain disallowed inline style attributes, which undermines the compiled treatment contract.",
|
|
2026
2026
|
evidence: buildSourceAuditEvidence(
|
|
2027
2027
|
sourceAudit,
|
|
2028
2028
|
sourceAudit.inlineStyles,
|
|
2029
|
-
"
|
|
2029
|
+
"Disallowed inline style attributes"
|
|
2030
2030
|
),
|
|
2031
|
-
suggestedFix: "Move
|
|
2031
|
+
suggestedFix: "Move static visual styling into treatments, atoms, or design-token-backed classes. Inline style remains acceptable for Decantr CSS-variable writes and truly dynamic geometry."
|
|
2032
2032
|
})
|
|
2033
2033
|
);
|
|
2034
2034
|
}
|
|
@@ -2894,7 +2894,7 @@ function appendSourceAuditFindings(findings, sourceAudit, essence, reviewPack) {
|
|
|
2894
2894
|
})
|
|
2895
2895
|
);
|
|
2896
2896
|
}
|
|
2897
|
-
if (topology.hasAuthFeature && topology.primaryRoutes.length > 0 && (sourceAudit.signInFlowSignals.count > 0 || sourceAudit.authEntrySignals.count > 0 && sourceAudit.signUpFlowSignals.count === 0 && sourceAudit.recoveryFlowSignals.count === 0) && sourceAudit.authProtectedRedirectSignals.count === 0) {
|
|
2897
|
+
if (topology.hasAuthFeature && topology.primaryRoutes.length > 0 && (sourceAudit.signInFlowSignals.count > 0 || sourceAudit.authEntrySignals.count > 0 && sourceAudit.signUpFlowSignals.count === 0 && sourceAudit.recoveryFlowSignals.count === 0) && sourceAudit.authProtectedRedirectSignals.count === 0 && sourceAudit.authSuccessSignals.count === 0) {
|
|
2898
2898
|
findings.push(
|
|
2899
2899
|
makeFinding({
|
|
2900
2900
|
id: "source-auth-success-redirect-missing",
|
|
@@ -4378,6 +4378,7 @@ function getSkipNavTargetId(attributes, tagName) {
|
|
|
4378
4378
|
function isAuthStorageKeyLiteral(node) {
|
|
4379
4379
|
if (!node) return false;
|
|
4380
4380
|
if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) {
|
|
4381
|
+
if (node.text === "decantr_authenticated") return false;
|
|
4381
4382
|
return /(?:token|auth|jwt|session|access_token|refresh_token)/i.test(node.text);
|
|
4382
4383
|
}
|
|
4383
4384
|
return false;
|
|
@@ -8745,6 +8746,87 @@ function countLocalhostEndpointSignals(code) {
|
|
|
8745
8746
|
function countWildcardPostMessageSignals(code) {
|
|
8746
8747
|
return code.match(/\bpostMessage\s*\([^)]*,\s*['"`]\*['"`]/g)?.length ?? 0;
|
|
8747
8748
|
}
|
|
8749
|
+
var DYNAMIC_GEOMETRY_STYLE_PROPS = /* @__PURE__ */ new Set([
|
|
8750
|
+
"top",
|
|
8751
|
+
"right",
|
|
8752
|
+
"bottom",
|
|
8753
|
+
"left",
|
|
8754
|
+
"inset",
|
|
8755
|
+
"width",
|
|
8756
|
+
"height",
|
|
8757
|
+
"minWidth",
|
|
8758
|
+
"minHeight",
|
|
8759
|
+
"maxWidth",
|
|
8760
|
+
"maxHeight",
|
|
8761
|
+
"transform",
|
|
8762
|
+
"transformOrigin",
|
|
8763
|
+
"opacity",
|
|
8764
|
+
"offsetPath",
|
|
8765
|
+
"offsetDistance",
|
|
8766
|
+
"cx",
|
|
8767
|
+
"cy",
|
|
8768
|
+
"x",
|
|
8769
|
+
"y"
|
|
8770
|
+
]);
|
|
8771
|
+
function getJsxAttributeExpression(initializer) {
|
|
8772
|
+
if (!initializer || !ts.isJsxExpression(initializer)) return null;
|
|
8773
|
+
return initializer.expression ?? null;
|
|
8774
|
+
}
|
|
8775
|
+
function getStylePropertyName(name) {
|
|
8776
|
+
if (ts.isIdentifier(name) || ts.isStringLiteral(name) || ts.isNumericLiteral(name)) {
|
|
8777
|
+
return name.text;
|
|
8778
|
+
}
|
|
8779
|
+
if (ts.isComputedPropertyName(name)) {
|
|
8780
|
+
return getExpressionLiteralValue(name.expression);
|
|
8781
|
+
}
|
|
8782
|
+
return null;
|
|
8783
|
+
}
|
|
8784
|
+
function unwrapStyleExpression(expression) {
|
|
8785
|
+
let current = expression;
|
|
8786
|
+
while (ts.isParenthesizedExpression(current) || ts.isAsExpression(current) || ts.isTypeAssertionExpression(current) || ts.isNonNullExpression(current) || ts.isSatisfiesExpression(current)) {
|
|
8787
|
+
current = current.expression;
|
|
8788
|
+
}
|
|
8789
|
+
return current;
|
|
8790
|
+
}
|
|
8791
|
+
function isDynamicStyleValue(expression) {
|
|
8792
|
+
const unwrapped = unwrapStyleExpression(expression);
|
|
8793
|
+
if (ts.isStringLiteral(unwrapped) || ts.isNoSubstitutionTemplateLiteral(unwrapped) || ts.isNumericLiteral(unwrapped) || unwrapped.kind === ts.SyntaxKind.TrueKeyword || unwrapped.kind === ts.SyntaxKind.FalseKeyword || unwrapped.kind === ts.SyntaxKind.NullKeyword) {
|
|
8794
|
+
return false;
|
|
8795
|
+
}
|
|
8796
|
+
return true;
|
|
8797
|
+
}
|
|
8798
|
+
function isAllowedInlineStyleObject(objectLiteral) {
|
|
8799
|
+
let sawGeometryProperty = false;
|
|
8800
|
+
let sawDynamicGeometryValue = false;
|
|
8801
|
+
for (const property of objectLiteral.properties) {
|
|
8802
|
+
if (!ts.isPropertyAssignment(property)) return false;
|
|
8803
|
+
const propertyName = getStylePropertyName(property.name);
|
|
8804
|
+
if (!propertyName) return false;
|
|
8805
|
+
if (propertyName.startsWith("--d-")) {
|
|
8806
|
+
continue;
|
|
8807
|
+
}
|
|
8808
|
+
if (!DYNAMIC_GEOMETRY_STYLE_PROPS.has(propertyName)) {
|
|
8809
|
+
return false;
|
|
8810
|
+
}
|
|
8811
|
+
sawGeometryProperty = true;
|
|
8812
|
+
if (isDynamicStyleValue(property.initializer)) {
|
|
8813
|
+
sawDynamicGeometryValue = true;
|
|
8814
|
+
}
|
|
8815
|
+
}
|
|
8816
|
+
return !sawGeometryProperty || sawDynamicGeometryValue;
|
|
8817
|
+
}
|
|
8818
|
+
function isAllowedInlineStyleAttribute(attribute, sourceFile, namedExpressions, namedPropertyAliases) {
|
|
8819
|
+
const expression = getJsxAttributeExpression(attribute.initializer);
|
|
8820
|
+
if (!expression) return false;
|
|
8821
|
+
const resolved = resolveObjectLiteralExpression(
|
|
8822
|
+
expression,
|
|
8823
|
+
sourceFile,
|
|
8824
|
+
namedExpressions,
|
|
8825
|
+
namedPropertyAliases,
|
|
8826
|
+
/* @__PURE__ */ new Set()
|
|
8827
|
+
);
|
|
8828
|
+
return resolved ? isAllowedInlineStyleObject(resolved.objectLiteral) : false;
|
|
8829
|
+
}
|
|
8748
8830
|
function analyzeAstSignals(filePath, code) {
|
|
8749
8831
|
const sourceFile = ts.createSourceFile(
|
|
8750
8832
|
filePath,
|
|
@@ -8836,7 +8918,14 @@ function analyzeAstSignals(filePath, code) {
|
|
|
8836
8918
|
const walk = (node) => {
|
|
8837
8919
|
if (ts.isJsxAttribute(node)) {
|
|
8838
8920
|
if (isPropertyNamed(node.name, "style") && node.initializer) {
|
|
8839
|
-
|
|
8921
|
+
if (!isAllowedInlineStyleAttribute(
|
|
8922
|
+
node,
|
|
8923
|
+
sourceFile,
|
|
8924
|
+
namedExpressionInitializers,
|
|
8925
|
+
namedPropertyAliases
|
|
8926
|
+
)) {
|
|
8927
|
+
signals.inlineStyleAttributeCount += 1;
|
|
8928
|
+
}
|
|
8840
8929
|
}
|
|
8841
8930
|
if (isPropertyNamed(node.name, "dangerouslySetInnerHTML")) {
|
|
8842
8931
|
signals.dangerousHtmlCount += 1;
|
|
@@ -10400,7 +10489,7 @@ function critiqueSource({
|
|
|
10400
10489
|
})
|
|
10401
10490
|
);
|
|
10402
10491
|
}
|
|
10403
|
-
const hasInlineStyleLiterals = astSignals.inlineStyleAttributeCount > 0 || /style\s*=\s*
|
|
10492
|
+
const hasInlineStyleLiterals = astSignals.inlineStyleAttributeCount > 0 || /style\s*=\s*["']/.test(code);
|
|
10404
10493
|
if (antiPatternIds.has("inline-styles") && hasInlineStyleLiterals) {
|
|
10405
10494
|
findings.push(
|
|
10406
10495
|
makeFinding({
|
|
@@ -10411,9 +10500,12 @@ function critiqueSource({
|
|
|
10411
10500
|
"theme-consistency"
|
|
10412
10501
|
]),
|
|
10413
10502
|
message: "Inline style literals were detected in the reviewed file.",
|
|
10414
|
-
evidence: [
|
|
10503
|
+
evidence: [
|
|
10504
|
+
filePath,
|
|
10505
|
+
`Disallowed inline style attributes: ${astSignals.inlineStyleAttributeCount}`
|
|
10506
|
+
],
|
|
10415
10507
|
file: filePath,
|
|
10416
|
-
suggestedFix: "Replace inline visual values with treatments, decorators, and CSS variables from the compiled contract."
|
|
10508
|
+
suggestedFix: "Replace static inline visual values with treatments, decorators, and CSS variables from the compiled contract. Keep inline style only for Decantr CSS-variable writes and truly dynamic geometry."
|
|
10417
10509
|
})
|
|
10418
10510
|
);
|
|
10419
10511
|
}
|