@synapsestudios/lintofu 0.0.0-stage → 0.9.0
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/LICENSE +661 -0
- package/README.md +151 -2
- package/dist/configs/category-recommended.d.ts +3 -0
- package/dist/configs/category-recommended.d.ts.map +1 -0
- package/dist/configs/category-recommended.js +12 -0
- package/dist/configs/category-recommended.js.map +1 -0
- package/dist/configs/recommended.d.ts +3 -0
- package/dist/configs/recommended.d.ts.map +1 -0
- package/dist/configs/recommended.js +12 -0
- package/dist/configs/recommended.js.map +1 -0
- package/dist/index.d.ts +198 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +65 -0
- package/dist/index.js.map +1 -0
- package/dist/language.d.ts +34 -0
- package/dist/language.d.ts.map +1 -0
- package/dist/language.js +72 -0
- package/dist/language.js.map +1 -0
- package/dist/parser/index.d.ts +10 -0
- package/dist/parser/index.d.ts.map +1 -0
- package/dist/parser/index.js +43 -0
- package/dist/parser/index.js.map +1 -0
- package/dist/parser/lintofu-parser.wasm +0 -0
- package/dist/parser/types.d.ts +261 -0
- package/dist/parser/types.d.ts.map +1 -0
- package/dist/parser/types.js +3 -0
- package/dist/parser/types.js.map +1 -0
- package/dist/parser/wasm-exec.cjs +575 -0
- package/dist/project-index.d.ts +40 -0
- package/dist/project-index.d.ts.map +1 -0
- package/dist/project-index.js +89 -0
- package/dist/project-index.js.map +1 -0
- package/dist/rules/aws/acm-certificate-create-before-destroy-required.d.ts +6 -0
- package/dist/rules/aws/acm-certificate-create-before-destroy-required.d.ts.map +1 -0
- package/dist/rules/aws/acm-certificate-create-before-destroy-required.js +47 -0
- package/dist/rules/aws/acm-certificate-create-before-destroy-required.js.map +1 -0
- package/dist/rules/aws/no-api-gateway-deployment-stage-args.d.ts +6 -0
- package/dist/rules/aws/no-api-gateway-deployment-stage-args.d.ts.map +1 -0
- package/dist/rules/aws/no-api-gateway-deployment-stage-args.js +56 -0
- package/dist/rules/aws/no-api-gateway-deployment-stage-args.js.map +1 -0
- package/dist/rules/aws/no-aurora-pinned-minor-with-auto-upgrade.d.ts +6 -0
- package/dist/rules/aws/no-aurora-pinned-minor-with-auto-upgrade.d.ts.map +1 -0
- package/dist/rules/aws/no-aurora-pinned-minor-with-auto-upgrade.js +88 -0
- package/dist/rules/aws/no-aurora-pinned-minor-with-auto-upgrade.js.map +1 -0
- package/dist/rules/aws/no-db-instance-name-attribute.d.ts +6 -0
- package/dist/rules/aws/no-db-instance-name-attribute.d.ts.map +1 -0
- package/dist/rules/aws/no-db-instance-name-attribute.js +45 -0
- package/dist/rules/aws/no-db-instance-name-attribute.js.map +1 -0
- package/dist/rules/aws/no-deprecated-lambda-runtime.d.ts +6 -0
- package/dist/rules/aws/no-deprecated-lambda-runtime.d.ts.map +1 -0
- package/dist/rules/aws/no-deprecated-lambda-runtime.js +91 -0
- package/dist/rules/aws/no-deprecated-lambda-runtime.js.map +1 -0
- package/dist/rules/aws/no-eip-vpc-attribute.d.ts +6 -0
- package/dist/rules/aws/no-eip-vpc-attribute.d.ts.map +1 -0
- package/dist/rules/aws/no-eip-vpc-attribute.js +66 -0
- package/dist/rules/aws/no-eip-vpc-attribute.js.map +1 -0
- package/dist/rules/aws/no-eks-addon-resolve-conflicts.d.ts +6 -0
- package/dist/rules/aws/no-eks-addon-resolve-conflicts.d.ts.map +1 -0
- package/dist/rules/aws/no-eks-addon-resolve-conflicts.js +36 -0
- package/dist/rules/aws/no-eks-addon-resolve-conflicts.js.map +1 -0
- package/dist/rules/aws/no-hardcoded-provider-credentials.d.ts +6 -0
- package/dist/rules/aws/no-hardcoded-provider-credentials.d.ts.map +1 -0
- package/dist/rules/aws/no-hardcoded-provider-credentials.js +42 -0
- package/dist/rules/aws/no-hardcoded-provider-credentials.js.map +1 -0
- package/dist/rules/aws/no-iam-policy-attachment.d.ts +6 -0
- package/dist/rules/aws/no-iam-policy-attachment.d.ts.map +1 -0
- package/dist/rules/aws/no-iam-policy-attachment.js +28 -0
- package/dist/rules/aws/no-iam-policy-attachment.js.map +1 -0
- package/dist/rules/aws/no-iam-role-inline-policies.d.ts +6 -0
- package/dist/rules/aws/no-iam-role-inline-policies.d.ts.map +1 -0
- package/dist/rules/aws/no-iam-role-inline-policies.js +43 -0
- package/dist/rules/aws/no-iam-role-inline-policies.js.map +1 -0
- package/dist/rules/aws/no-instance-cpu-count-attributes.d.ts +6 -0
- package/dist/rules/aws/no-instance-cpu-count-attributes.d.ts.map +1 -0
- package/dist/rules/aws/no-instance-cpu-count-attributes.js +94 -0
- package/dist/rules/aws/no-instance-cpu-count-attributes.js.map +1 -0
- package/dist/rules/aws/no-legacy-security-group-rules.d.ts +6 -0
- package/dist/rules/aws/no-legacy-security-group-rules.d.ts.map +1 -0
- package/dist/rules/aws/no-legacy-security-group-rules.js +39 -0
- package/dist/rules/aws/no-legacy-security-group-rules.js.map +1 -0
- package/dist/rules/aws/no-mixed-security-group-rule-forms.d.ts +6 -0
- package/dist/rules/aws/no-mixed-security-group-rule-forms.d.ts.map +1 -0
- package/dist/rules/aws/no-mixed-security-group-rule-forms.js +63 -0
- package/dist/rules/aws/no-mixed-security-group-rule-forms.js.map +1 -0
- package/dist/rules/aws/no-pinned-minor-with-auto-upgrade.d.ts +6 -0
- package/dist/rules/aws/no-pinned-minor-with-auto-upgrade.d.ts.map +1 -0
- package/dist/rules/aws/no-pinned-minor-with-auto-upgrade.js +100 -0
- package/dist/rules/aws/no-pinned-minor-with-auto-upgrade.js.map +1 -0
- package/dist/rules/aws/no-s3-bucket-inline-config.d.ts +6 -0
- package/dist/rules/aws/no-s3-bucket-inline-config.d.ts.map +1 -0
- package/dist/rules/aws/no-s3-bucket-inline-config.js +67 -0
- package/dist/rules/aws/no-s3-bucket-inline-config.js.map +1 -0
- package/dist/rules/aws/no-s3-bucket-object.d.ts +6 -0
- package/dist/rules/aws/no-s3-bucket-object.d.ts.map +1 -0
- package/dist/rules/aws/no-s3-bucket-object.js +41 -0
- package/dist/rules/aws/no-s3-bucket-object.js.map +1 -0
- package/dist/rules/aws/utils.d.ts +4 -0
- package/dist/rules/aws/utils.d.ts.map +1 -0
- package/dist/rules/aws/utils.js +17 -0
- package/dist/rules/aws/utils.js.map +1 -0
- package/dist/rules/cloudflare/access-rule-country-block-requires-enterprise.d.ts +6 -0
- package/dist/rules/cloudflare/access-rule-country-block-requires-enterprise.d.ts.map +1 -0
- package/dist/rules/cloudflare/access-rule-country-block-requires-enterprise.js +66 -0
- package/dist/rules/cloudflare/access-rule-country-block-requires-enterprise.js.map +1 -0
- package/dist/rules/cloudflare/dns-record-requires-managed-by-annotation.d.ts +10 -0
- package/dist/rules/cloudflare/dns-record-requires-managed-by-annotation.d.ts.map +1 -0
- package/dist/rules/cloudflare/dns-record-requires-managed-by-annotation.js +104 -0
- package/dist/rules/cloudflare/dns-record-requires-managed-by-annotation.js.map +1 -0
- package/dist/rules/cloudflare/ruleset-requires-managed-by-description.d.ts +9 -0
- package/dist/rules/cloudflare/ruleset-requires-managed-by-description.d.ts.map +1 -0
- package/dist/rules/cloudflare/ruleset-requires-managed-by-description.js +52 -0
- package/dist/rules/cloudflare/ruleset-requires-managed-by-description.js.map +1 -0
- package/dist/rules/cloudflare/utils.d.ts +17 -0
- package/dist/rules/cloudflare/utils.d.ts.map +1 -0
- package/dist/rules/cloudflare/utils.js +37 -0
- package/dist/rules/cloudflare/utils.js.map +1 -0
- package/dist/rules/core/documented-outputs.d.ts +6 -0
- package/dist/rules/core/documented-outputs.d.ts.map +1 -0
- package/dist/rules/core/documented-outputs.js +41 -0
- package/dist/rules/core/documented-outputs.js.map +1 -0
- package/dist/rules/core/documented-variables.d.ts +6 -0
- package/dist/rules/core/documented-variables.d.ts.map +1 -0
- package/dist/rules/core/documented-variables.js +41 -0
- package/dist/rules/core/documented-variables.js.map +1 -0
- package/dist/rules/core/module-source-pinned.d.ts +6 -0
- package/dist/rules/core/module-source-pinned.d.ts.map +1 -0
- package/dist/rules/core/module-source-pinned.js +47 -0
- package/dist/rules/core/module-source-pinned.js.map +1 -0
- package/dist/rules/core/no-bool-as-count.d.ts +6 -0
- package/dist/rules/core/no-bool-as-count.d.ts.map +1 -0
- package/dist/rules/core/no-bool-as-count.js +69 -0
- package/dist/rules/core/no-bool-as-count.js.map +1 -0
- package/dist/rules/core/no-duplicate-map-keys.d.ts +6 -0
- package/dist/rules/core/no-duplicate-map-keys.d.ts.map +1 -0
- package/dist/rules/core/no-duplicate-map-keys.js +42 -0
- package/dist/rules/core/no-duplicate-map-keys.js.map +1 -0
- package/dist/rules/core/no-empty-list-equality.d.ts +6 -0
- package/dist/rules/core/no-empty-list-equality.d.ts.map +1 -0
- package/dist/rules/core/no-empty-list-equality.js +48 -0
- package/dist/rules/core/no-empty-list-equality.js.map +1 -0
- package/dist/rules/core/no-external-refs-in-destroy-provisioner.d.ts +6 -0
- package/dist/rules/core/no-external-refs-in-destroy-provisioner.d.ts.map +1 -0
- package/dist/rules/core/no-external-refs-in-destroy-provisioner.js +74 -0
- package/dist/rules/core/no-external-refs-in-destroy-provisioner.js.map +1 -0
- package/dist/rules/core/no-legacy-count-attribute.d.ts +6 -0
- package/dist/rules/core/no-legacy-count-attribute.d.ts.map +1 -0
- package/dist/rules/core/no-legacy-count-attribute.js +64 -0
- package/dist/rules/core/no-legacy-count-attribute.js.map +1 -0
- package/dist/rules/core/no-legacy-dot-index.d.ts +6 -0
- package/dist/rules/core/no-legacy-dot-index.d.ts.map +1 -0
- package/dist/rules/core/no-legacy-dot-index.js +79 -0
- package/dist/rules/core/no-legacy-dot-index.js.map +1 -0
- package/dist/rules/core/no-legacy-ignore-changes-wildcard.d.ts +6 -0
- package/dist/rules/core/no-legacy-ignore-changes-wildcard.d.ts.map +1 -0
- package/dist/rules/core/no-legacy-ignore-changes-wildcard.js +40 -0
- package/dist/rules/core/no-legacy-ignore-changes-wildcard.js.map +1 -0
- package/dist/rules/core/no-legacy-list-function.d.ts +6 -0
- package/dist/rules/core/no-legacy-list-function.d.ts.map +1 -0
- package/dist/rules/core/no-legacy-list-function.js +67 -0
- package/dist/rules/core/no-legacy-list-function.js.map +1 -0
- package/dist/rules/core/no-legacy-lookup.d.ts +6 -0
- package/dist/rules/core/no-legacy-lookup.d.ts.map +1 -0
- package/dist/rules/core/no-legacy-lookup.js +53 -0
- package/dist/rules/core/no-legacy-lookup.js.map +1 -0
- package/dist/rules/core/no-legacy-map-function.d.ts +6 -0
- package/dist/rules/core/no-legacy-map-function.d.ts.map +1 -0
- package/dist/rules/core/no-legacy-map-function.js +90 -0
- package/dist/rules/core/no-legacy-map-function.js.map +1 -0
- package/dist/rules/core/no-legacy-provider-proxy.d.ts +6 -0
- package/dist/rules/core/no-legacy-provider-proxy.d.ts.map +1 -0
- package/dist/rules/core/no-legacy-provider-proxy.js +43 -0
- package/dist/rules/core/no-legacy-provider-proxy.js.map +1 -0
- package/dist/rules/core/no-provider-version-constraint.d.ts +6 -0
- package/dist/rules/core/no-provider-version-constraint.d.ts.map +1 -0
- package/dist/rules/core/no-provider-version-constraint.js +33 -0
- package/dist/rules/core/no-provider-version-constraint.js.map +1 -0
- package/dist/rules/core/no-quoted-depends-on.d.ts +6 -0
- package/dist/rules/core/no-quoted-depends-on.d.ts.map +1 -0
- package/dist/rules/core/no-quoted-depends-on.js +55 -0
- package/dist/rules/core/no-quoted-depends-on.js.map +1 -0
- package/dist/rules/core/no-quoted-ignore-changes.d.ts +6 -0
- package/dist/rules/core/no-quoted-ignore-changes.d.ts.map +1 -0
- package/dist/rules/core/no-quoted-ignore-changes.js +63 -0
- package/dist/rules/core/no-quoted-ignore-changes.js.map +1 -0
- package/dist/rules/core/no-quoted-provider-reference.d.ts +6 -0
- package/dist/rules/core/no-quoted-provider-reference.d.ts.map +1 -0
- package/dist/rules/core/no-quoted-provider-reference.js +69 -0
- package/dist/rules/core/no-quoted-provider-reference.js.map +1 -0
- package/dist/rules/core/no-quoted-type-constraints.d.ts +6 -0
- package/dist/rules/core/no-quoted-type-constraints.d.ts.map +1 -0
- package/dist/rules/core/no-quoted-type-constraints.js +55 -0
- package/dist/rules/core/no-quoted-type-constraints.js.map +1 -0
- package/dist/rules/core/no-reserved-variable-names.d.ts +6 -0
- package/dist/rules/core/no-reserved-variable-names.d.ts.map +1 -0
- package/dist/rules/core/no-reserved-variable-names.js +41 -0
- package/dist/rules/core/no-reserved-variable-names.js.map +1 -0
- package/dist/rules/core/no-splat-bracket-index.d.ts +6 -0
- package/dist/rules/core/no-splat-bracket-index.d.ts.map +1 -0
- package/dist/rules/core/no-splat-bracket-index.js +30 -0
- package/dist/rules/core/no-splat-bracket-index.js.map +1 -0
- package/dist/rules/core/no-template-provider.d.ts +6 -0
- package/dist/rules/core/no-template-provider.d.ts.map +1 -0
- package/dist/rules/core/no-template-provider.js +63 -0
- package/dist/rules/core/no-template-provider.js.map +1 -0
- package/dist/rules/core/no-terraform-env-reference.d.ts +6 -0
- package/dist/rules/core/no-terraform-env-reference.d.ts.map +1 -0
- package/dist/rules/core/no-terraform-env-reference.js +35 -0
- package/dist/rules/core/no-terraform-env-reference.js.map +1 -0
- package/dist/rules/core/no-winrm-connection.d.ts +6 -0
- package/dist/rules/core/no-winrm-connection.d.ts.map +1 -0
- package/dist/rules/core/no-winrm-connection.js +31 -0
- package/dist/rules/core/no-winrm-connection.js.map +1 -0
- package/dist/rules/core/prefer-bare-expression.d.ts +6 -0
- package/dist/rules/core/prefer-bare-expression.d.ts.map +1 -0
- package/dist/rules/core/prefer-bare-expression.js +23 -0
- package/dist/rules/core/prefer-bare-expression.js.map +1 -0
- package/dist/rules/core/provider-source-required.d.ts +6 -0
- package/dist/rules/core/provider-source-required.d.ts.map +1 -0
- package/dist/rules/core/provider-source-required.js +45 -0
- package/dist/rules/core/provider-source-required.js.map +1 -0
- package/dist/rules/core/remote-state-outputs-prefix.d.ts +6 -0
- package/dist/rules/core/remote-state-outputs-prefix.d.ts.map +1 -0
- package/dist/rules/core/remote-state-outputs-prefix.js +54 -0
- package/dist/rules/core/remote-state-outputs-prefix.js.map +1 -0
- package/dist/rules/core/required-providers-pinned.d.ts +6 -0
- package/dist/rules/core/required-providers-pinned.d.ts.map +1 -0
- package/dist/rules/core/required-providers-pinned.js +37 -0
- package/dist/rules/core/required-providers-pinned.js.map +1 -0
- package/dist/rules/core/required-version-declared.d.ts +6 -0
- package/dist/rules/core/required-version-declared.d.ts.map +1 -0
- package/dist/rules/core/required-version-declared.js +38 -0
- package/dist/rules/core/required-version-declared.js.map +1 -0
- package/dist/rules/core/typed-variables.d.ts +6 -0
- package/dist/rules/core/typed-variables.d.ts.map +1 -0
- package/dist/rules/core/typed-variables.js +32 -0
- package/dist/rules/core/typed-variables.js.map +1 -0
- package/dist/rules/core/utils.d.ts +31 -0
- package/dist/rules/core/utils.d.ts.map +1 -0
- package/dist/rules/core/utils.js +185 -0
- package/dist/rules/core/utils.js.map +1 -0
- package/dist/rules/index.d.ts +157 -0
- package/dist/rules/index.d.ts.map +1 -0
- package/dist/rules/index.js +101 -0
- package/dist/rules/index.js.map +1 -0
- package/dist/rules/types.d.ts +57 -0
- package/dist/rules/types.d.ts.map +1 -0
- package/dist/rules/types.js +15 -0
- package/dist/rules/types.js.map +1 -0
- package/dist/source-code.d.ts +84 -0
- package/dist/source-code.d.ts.map +1 -0
- package/dist/source-code.js +170 -0
- package/dist/source-code.js.map +1 -0
- package/dist/types.d.ts +67 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/visitor-keys.d.ts +3 -0
- package/dist/visitor-keys.d.ts.map +1 -0
- package/dist/visitor-keys.js +30 -0
- package/dist/visitor-keys.js.map +1 -0
- package/package.json +88 -4
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { findAttribute, literalStringValue } from '../core/utils.js';
|
|
2
|
+
export function engineName(block) {
|
|
3
|
+
const attr = findAttribute(block.body.attributes, 'engine');
|
|
4
|
+
if (!attr)
|
|
5
|
+
return undefined;
|
|
6
|
+
return literalStringValue(attr.expression);
|
|
7
|
+
}
|
|
8
|
+
export function autoMinorUpgradeEnabled(block) {
|
|
9
|
+
const attr = findAttribute(block.body.attributes, 'auto_minor_version_upgrade');
|
|
10
|
+
if (!attr)
|
|
11
|
+
return true;
|
|
12
|
+
const expr = attr.expression;
|
|
13
|
+
if (expr.type !== 'LiteralValueExpr')
|
|
14
|
+
return false;
|
|
15
|
+
return expr.value !== false;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/rules/aws/utils.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAErE,MAAM,UAAU,UAAU,CAAC,KAAY;IACrC,MAAM,IAAI,GAAG,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IAC5D,IAAI,CAAC,IAAI;QAAE,OAAO,SAAS,CAAC;IAC5B,OAAO,kBAAkB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;AAC7C,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,KAAY;IAClD,MAAM,IAAI,GAAG,aAAa,CACxB,KAAK,CAAC,IAAI,CAAC,UAAU,EACrB,4BAA4B,CAC7B,CAAC;IACF,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IACvB,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC;IAC7B,IAAI,IAAI,CAAC,IAAI,KAAK,kBAAkB;QAAE,OAAO,KAAK,CAAC;IACnD,OAAO,IAAI,CAAC,KAAK,KAAK,KAAK,CAAC;AAC9B,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { OpenTofuRuleDefinition } from '../../types.js';
|
|
2
|
+
declare const rule: OpenTofuRuleDefinition<{
|
|
3
|
+
MessageIds: 'countryBlockRequiresEnterprise' | 'invalidPlan';
|
|
4
|
+
}>;
|
|
5
|
+
export default rule;
|
|
6
|
+
//# sourceMappingURL=access-rule-country-block-requires-enterprise.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"access-rule-country-block-requires-enterprise.d.ts","sourceRoot":"","sources":["../../../src/rules/cloudflare/access-rule-country-block-requires-enterprise.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AA6B7D,QAAA,MAAM,IAAI,EAAE,sBAAsB,CAAC;IACjC,UAAU,EAAE,gCAAgC,GAAG,aAAa,CAAC;CAC9D,CAgDA,CAAC;AAEF,eAAe,IAAI,CAAC"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { findAttribute, literalAttributeValue, literalStringValue, objectItemKeyName, } from '../core/utils.js';
|
|
2
|
+
import { entitlesCountryBlock, INVALID_PLAN_MESSAGE, readCloudflarePlan, } from './utils.js';
|
|
3
|
+
function configurationTarget(block) {
|
|
4
|
+
const attr = findAttribute(block.body.attributes, 'configuration');
|
|
5
|
+
if (attr?.expression.type !== 'ObjectConsExpr')
|
|
6
|
+
return undefined;
|
|
7
|
+
const target = attr.expression.items.find((item) => objectItemKeyName(item) === 'target');
|
|
8
|
+
return target ? literalStringValue(target.valueExpr) : undefined;
|
|
9
|
+
}
|
|
10
|
+
function blocksByCountry(block) {
|
|
11
|
+
return (literalAttributeValue(block, 'mode') === 'block' &&
|
|
12
|
+
configurationTarget(block) === 'country');
|
|
13
|
+
}
|
|
14
|
+
const rule = {
|
|
15
|
+
meta: {
|
|
16
|
+
type: 'problem',
|
|
17
|
+
docs: {
|
|
18
|
+
description: 'Flag a `cloudflare_access_rule` that blocks by country while `settings.lintofu.cloudflare.plan` is below Enterprise, the only plan Cloudflare allows it on.',
|
|
19
|
+
recommended: true,
|
|
20
|
+
severity: 'error',
|
|
21
|
+
category: 'cloudflare',
|
|
22
|
+
appliesTo: { cloudflare: '>=5.0.0' },
|
|
23
|
+
},
|
|
24
|
+
messages: {
|
|
25
|
+
countryBlockRequiresEnterprise: 'Blocking by country in a Cloudflare IP Access rule requires the Enterprise plan. The configured plan is "{{plan}}", so this resource fails at apply.',
|
|
26
|
+
invalidPlan: INVALID_PLAN_MESSAGE,
|
|
27
|
+
},
|
|
28
|
+
schema: [],
|
|
29
|
+
},
|
|
30
|
+
create(context) {
|
|
31
|
+
const setting = readCloudflarePlan(context.settings);
|
|
32
|
+
if (setting.state === 'invalid') {
|
|
33
|
+
return {
|
|
34
|
+
Body(node) {
|
|
35
|
+
if (node !== context.sourceCode.ast)
|
|
36
|
+
return;
|
|
37
|
+
context.report({
|
|
38
|
+
node,
|
|
39
|
+
messageId: 'invalidPlan',
|
|
40
|
+
data: { value: setting.value },
|
|
41
|
+
});
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
if (setting.state === 'unset' || entitlesCountryBlock(setting.plan)) {
|
|
46
|
+
return {};
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
Block(node) {
|
|
50
|
+
if (node.kind !== 'resource')
|
|
51
|
+
return;
|
|
52
|
+
if (node.labels[0] !== 'cloudflare_access_rule')
|
|
53
|
+
return;
|
|
54
|
+
if (!blocksByCountry(node))
|
|
55
|
+
return;
|
|
56
|
+
context.report({
|
|
57
|
+
node,
|
|
58
|
+
messageId: 'countryBlockRequiresEnterprise',
|
|
59
|
+
data: { plan: setting.plan },
|
|
60
|
+
});
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
export default rule;
|
|
66
|
+
//# sourceMappingURL=access-rule-country-block-requires-enterprise.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"access-rule-country-block-requires-enterprise.js","sourceRoot":"","sources":["../../../src/rules/cloudflare/access-rule-country-block-requires-enterprise.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,aAAa,EACb,qBAAqB,EACrB,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,YAAY,CAAC;AAEpB,SAAS,mBAAmB,CAAC,KAAY;IACvC,MAAM,IAAI,GAAG,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,EAAE,eAAe,CAAC,CAAC;IACnE,IAAI,IAAI,EAAE,UAAU,CAAC,IAAI,KAAK,gBAAgB;QAAE,OAAO,SAAS,CAAC;IACjE,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,CACvC,CAAC,IAAI,EAAE,EAAE,CAAC,iBAAiB,CAAC,IAAI,CAAC,KAAK,QAAQ,CAC/C,CAAC;IACF,OAAO,MAAM,CAAC,CAAC,CAAC,kBAAkB,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACnE,CAAC;AAED,SAAS,eAAe,CAAC,KAAY;IACnC,OAAO,CACL,qBAAqB,CAAC,KAAK,EAAE,MAAM,CAAC,KAAK,OAAO;QAChD,mBAAmB,CAAC,KAAK,CAAC,KAAK,SAAS,CACzC,CAAC;AACJ,CAAC;AAED,MAAM,IAAI,GAEL;IACH,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACJ,WAAW,EACT,6JAA6J;YAC/J,WAAW,EAAE,IAAI;YACjB,QAAQ,EAAE,OAAO;YACjB,QAAQ,EAAE,YAAY;YACtB,SAAS,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE;SACrC;QACD,QAAQ,EAAE;YACR,8BAA8B,EAC5B,sJAAsJ;YACxJ,WAAW,EAAE,oBAAoB;SAClC;QACD,MAAM,EAAE,EAAE;KACX;IACD,MAAM,CAAC,OAAO;QACZ,MAAM,OAAO,GAAG,kBAAkB,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACrD,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;YAChC,OAAO;gBACL,IAAI,CAAC,IAAI;oBACP,IAAI,IAAI,KAAK,OAAO,CAAC,UAAU,CAAC,GAAG;wBAAE,OAAO;oBAC5C,OAAO,CAAC,MAAM,CAAC;wBACb,IAAI;wBACJ,SAAS,EAAE,aAAa;wBACxB,IAAI,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE;qBAC/B,CAAC,CAAC;gBACL,CAAC;aACF,CAAC;QACJ,CAAC;QACD,IAAI,OAAO,CAAC,KAAK,KAAK,OAAO,IAAI,oBAAoB,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YACpE,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,OAAO;YACL,KAAK,CAAC,IAAI;gBACR,IAAI,IAAI,CAAC,IAAI,KAAK,UAAU;oBAAE,OAAO;gBACrC,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,wBAAwB;oBAAE,OAAO;gBACxD,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC;oBAAE,OAAO;gBACnC,OAAO,CAAC,MAAM,CAAC;oBACb,IAAI;oBACJ,SAAS,EAAE,gCAAgC;oBAC3C,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE;iBAC7B,CAAC,CAAC;YACL,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,eAAe,IAAI,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { OpenTofuRuleDefinition } from '../../types.js';
|
|
2
|
+
declare const rule: OpenTofuRuleDefinition<{
|
|
3
|
+
RuleOptions: [{
|
|
4
|
+
comment?: string;
|
|
5
|
+
tag?: string;
|
|
6
|
+
}?];
|
|
7
|
+
MessageIds: 'missingComment' | 'missingTag' | 'invalidPlan';
|
|
8
|
+
}>;
|
|
9
|
+
export default rule;
|
|
10
|
+
//# sourceMappingURL=dns-record-requires-managed-by-annotation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dns-record-requires-managed-by-annotation.d.ts","sourceRoot":"","sources":["../../../src/rules/cloudflare/dns-record-requires-managed-by-annotation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAuC7D,QAAA,MAAM,IAAI,EAAE,sBAAsB,CAAC;IACjC,WAAW,EAAE,CAAC;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAC;IACnD,UAAU,EAAE,gBAAgB,GAAG,YAAY,GAAG,aAAa,CAAC;CAC7D,CA+EA,CAAC;AAEF,eAAe,IAAI,CAAC"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { findAttribute, findLiteralMismatch, literalStringValue, } from '../core/utils.js';
|
|
2
|
+
import { entitlesDnsRecordTags, INVALID_PLAN_MESSAGE, readCloudflarePlan, } from './utils.js';
|
|
3
|
+
const DEFAULT_COMMENT = 'Managed by terraform';
|
|
4
|
+
const DEFAULT_TAG = 'managed-by:terraform';
|
|
5
|
+
// Cloudflare compares tag names without case and tag values with case.
|
|
6
|
+
function tagsMatch(candidate, tag) {
|
|
7
|
+
const [candidateName, ...candidateValue] = candidate.split(':');
|
|
8
|
+
const [tagName, ...tagValue] = tag.split(':');
|
|
9
|
+
return (candidateName?.toLowerCase() === tagName?.toLowerCase() &&
|
|
10
|
+
candidateValue.join(':') === tagValue.join(':'));
|
|
11
|
+
}
|
|
12
|
+
function findMissingTag(block, tag) {
|
|
13
|
+
const attr = findAttribute(block.body.attributes, 'tags');
|
|
14
|
+
if (!attr)
|
|
15
|
+
return block;
|
|
16
|
+
if (attr.expression.type !== 'TupleConsExpr')
|
|
17
|
+
return undefined;
|
|
18
|
+
const values = attr.expression.exprs.map(literalStringValue);
|
|
19
|
+
if (values.some((value) => value !== undefined && tagsMatch(value, tag))) {
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
return values.includes(undefined) ? undefined : attr;
|
|
23
|
+
}
|
|
24
|
+
const rule = {
|
|
25
|
+
meta: {
|
|
26
|
+
type: 'suggestion',
|
|
27
|
+
docs: {
|
|
28
|
+
description: 'Require a `cloudflare_dns_record` to carry the configured `comment`, plus the configured tag when `settings.lintofu.cloudflare.plan` is Pro or higher, so the record shows it is managed by Terraform.',
|
|
29
|
+
recommended: true,
|
|
30
|
+
severity: 'warn',
|
|
31
|
+
category: 'cloudflare',
|
|
32
|
+
appliesTo: { cloudflare: '>=5.0.0' },
|
|
33
|
+
},
|
|
34
|
+
messages: {
|
|
35
|
+
missingComment: 'Set the DNS record `comment` to "{{comment}}" to mark it as managed by Terraform.',
|
|
36
|
+
missingTag: 'Add "{{tag}}" to the DNS record `tags` to mark it as managed by Terraform. The configured "{{plan}}" plan supports DNS record tags.',
|
|
37
|
+
invalidPlan: INVALID_PLAN_MESSAGE,
|
|
38
|
+
},
|
|
39
|
+
schema: [
|
|
40
|
+
{
|
|
41
|
+
type: 'object',
|
|
42
|
+
properties: {
|
|
43
|
+
comment: {
|
|
44
|
+
type: 'string',
|
|
45
|
+
description: 'The exact `comment` that marks a DNS record as managed by Terraform.',
|
|
46
|
+
},
|
|
47
|
+
tag: {
|
|
48
|
+
type: 'string',
|
|
49
|
+
description: 'The `name:value` tag that marks a DNS record as managed by Terraform. The name matches without case and the value with case.',
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
additionalProperties: false,
|
|
53
|
+
},
|
|
54
|
+
],
|
|
55
|
+
defaultOptions: [{ comment: DEFAULT_COMMENT, tag: DEFAULT_TAG }],
|
|
56
|
+
},
|
|
57
|
+
create(context) {
|
|
58
|
+
const comment = context.options[0]?.comment ?? DEFAULT_COMMENT;
|
|
59
|
+
const tag = context.options[0]?.tag ?? DEFAULT_TAG;
|
|
60
|
+
const setting = readCloudflarePlan(context.settings);
|
|
61
|
+
const tagPlan = setting.state === 'valid' && entitlesDnsRecordTags(setting.plan)
|
|
62
|
+
? setting.plan
|
|
63
|
+
: undefined;
|
|
64
|
+
return {
|
|
65
|
+
Body(node) {
|
|
66
|
+
if (setting.state !== 'invalid')
|
|
67
|
+
return;
|
|
68
|
+
if (node !== context.sourceCode.ast)
|
|
69
|
+
return;
|
|
70
|
+
context.report({
|
|
71
|
+
node,
|
|
72
|
+
messageId: 'invalidPlan',
|
|
73
|
+
data: { value: setting.value },
|
|
74
|
+
});
|
|
75
|
+
},
|
|
76
|
+
Block(node) {
|
|
77
|
+
if (node.kind !== 'resource')
|
|
78
|
+
return;
|
|
79
|
+
if (node.labels[0] !== 'cloudflare_dns_record')
|
|
80
|
+
return;
|
|
81
|
+
const commentMismatch = findLiteralMismatch(node, 'comment', comment);
|
|
82
|
+
if (commentMismatch) {
|
|
83
|
+
context.report({
|
|
84
|
+
node: commentMismatch,
|
|
85
|
+
messageId: 'missingComment',
|
|
86
|
+
data: { comment },
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
if (tagPlan === undefined)
|
|
90
|
+
return;
|
|
91
|
+
const missingTag = findMissingTag(node, tag);
|
|
92
|
+
if (missingTag) {
|
|
93
|
+
context.report({
|
|
94
|
+
node: missingTag,
|
|
95
|
+
messageId: 'missingTag',
|
|
96
|
+
data: { tag, plan: tagPlan },
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
export default rule;
|
|
104
|
+
//# sourceMappingURL=dns-record-requires-managed-by-annotation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dns-record-requires-managed-by-annotation.js","sourceRoot":"","sources":["../../../src/rules/cloudflare/dns-record-requires-managed-by-annotation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { OpenTofuRuleDefinition } from '../../types.js';
|
|
2
|
+
declare const rule: OpenTofuRuleDefinition<{
|
|
3
|
+
RuleOptions: [{
|
|
4
|
+
description?: string;
|
|
5
|
+
}?];
|
|
6
|
+
MessageIds: 'missingDescription';
|
|
7
|
+
}>;
|
|
8
|
+
export default rule;
|
|
9
|
+
//# sourceMappingURL=ruleset-requires-managed-by-description.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ruleset-requires-managed-by-description.d.ts","sourceRoot":"","sources":["../../../src/rules/cloudflare/ruleset-requires-managed-by-description.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAK7D,QAAA,MAAM,IAAI,EAAE,sBAAsB,CAAC;IACjC,WAAW,EAAE,CAAC;QAAE,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAC;IACzC,UAAU,EAAE,oBAAoB,CAAC;CAClC,CA8CA,CAAC;AAEF,eAAe,IAAI,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { findLiteralMismatch, literalAttributeValue } from '../core/utils.js';
|
|
2
|
+
const DEFAULT_DESCRIPTION = 'Managed by terraform';
|
|
3
|
+
const rule = {
|
|
4
|
+
meta: {
|
|
5
|
+
type: 'suggestion',
|
|
6
|
+
docs: {
|
|
7
|
+
description: 'Require a `cloudflare_ruleset` to set its top-level `description` to the configured marker, so the ruleset shows it is managed by Terraform.',
|
|
8
|
+
recommended: true,
|
|
9
|
+
severity: 'warn',
|
|
10
|
+
category: 'cloudflare',
|
|
11
|
+
},
|
|
12
|
+
messages: {
|
|
13
|
+
missingDescription: 'Set the ruleset `description` to "{{description}}" to mark it as managed by Terraform.',
|
|
14
|
+
},
|
|
15
|
+
schema: [
|
|
16
|
+
{
|
|
17
|
+
type: 'object',
|
|
18
|
+
properties: {
|
|
19
|
+
description: {
|
|
20
|
+
type: 'string',
|
|
21
|
+
description: 'The exact top-level `description` that marks a ruleset as managed by Terraform.',
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
additionalProperties: false,
|
|
25
|
+
},
|
|
26
|
+
],
|
|
27
|
+
defaultOptions: [{ description: DEFAULT_DESCRIPTION }],
|
|
28
|
+
},
|
|
29
|
+
create(context) {
|
|
30
|
+
const description = context.options[0]?.description ?? DEFAULT_DESCRIPTION;
|
|
31
|
+
return {
|
|
32
|
+
Block(node) {
|
|
33
|
+
if (node.kind !== 'resource')
|
|
34
|
+
return;
|
|
35
|
+
if (node.labels[0] !== 'cloudflare_ruleset')
|
|
36
|
+
return;
|
|
37
|
+
if (literalAttributeValue(node, 'kind') === 'managed')
|
|
38
|
+
return;
|
|
39
|
+
const mismatch = findLiteralMismatch(node, 'description', description);
|
|
40
|
+
if (!mismatch)
|
|
41
|
+
return;
|
|
42
|
+
context.report({
|
|
43
|
+
node: mismatch,
|
|
44
|
+
messageId: 'missingDescription',
|
|
45
|
+
data: { description },
|
|
46
|
+
});
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
export default rule;
|
|
52
|
+
//# sourceMappingURL=ruleset-requires-managed-by-description.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ruleset-requires-managed-by-description.js","sourceRoot":"","sources":["../../../src/rules/cloudflare/ruleset-requires-managed-by-description.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAE9E,MAAM,mBAAmB,GAAG,sBAAsB,CAAC;AAEnD,MAAM,IAAI,GAGL;IACH,IAAI,EAAE;QACJ,IAAI,EAAE,YAAY;QAClB,IAAI,EAAE;YACJ,WAAW,EACT,8IAA8I;YAChJ,WAAW,EAAE,IAAI;YACjB,QAAQ,EAAE,MAAM;YAChB,QAAQ,EAAE,YAAY;SACvB;QACD,QAAQ,EAAE;YACR,kBAAkB,EAChB,wFAAwF;SAC3F;QACD,MAAM,EAAE;YACN;gBACE,IAAI,EAAE,QAAQ;gBACd,UAAU,EAAE;oBACV,WAAW,EAAE;wBACX,IAAI,EAAE,QAAQ;wBACd,WAAW,EACT,iFAAiF;qBACpF;iBACF;gBACD,oBAAoB,EAAE,KAAK;aAC5B;SACF;QACD,cAAc,EAAE,CAAC,EAAE,WAAW,EAAE,mBAAmB,EAAE,CAAC;KACvD;IACD,MAAM,CAAC,OAAO;QACZ,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,WAAW,IAAI,mBAAmB,CAAC;QAC3E,OAAO;YACL,KAAK,CAAC,IAAI;gBACR,IAAI,IAAI,CAAC,IAAI,KAAK,UAAU;oBAAE,OAAO;gBACrC,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,oBAAoB;oBAAE,OAAO;gBACpD,IAAI,qBAAqB,CAAC,IAAI,EAAE,MAAM,CAAC,KAAK,SAAS;oBAAE,OAAO;gBAC9D,MAAM,QAAQ,GAAG,mBAAmB,CAAC,IAAI,EAAE,aAAa,EAAE,WAAW,CAAC,CAAC;gBACvE,IAAI,CAAC,QAAQ;oBAAE,OAAO;gBACtB,OAAO,CAAC,MAAM,CAAC;oBACb,IAAI,EAAE,QAAQ;oBACd,SAAS,EAAE,oBAAoB;oBAC/B,IAAI,EAAE,EAAE,WAAW,EAAE;iBACtB,CAAC,CAAC;YACL,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,eAAe,IAAI,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { SettingsConfig } from '@eslint/core';
|
|
2
|
+
export declare const CLOUDFLARE_PLANS: readonly ["free", "pro", "business", "enterprise"];
|
|
3
|
+
export declare const INVALID_PLAN_MESSAGE = "Unrecognized Cloudflare plan \"{{value}}\" in `settings.lintofu.cloudflare.plan`. Accepted values are `free`, `pro`, `business`, and `enterprise`.";
|
|
4
|
+
export type CloudflarePlan = (typeof CLOUDFLARE_PLANS)[number];
|
|
5
|
+
export type PlanSetting = {
|
|
6
|
+
state: 'unset';
|
|
7
|
+
} | {
|
|
8
|
+
state: 'valid';
|
|
9
|
+
plan: CloudflarePlan;
|
|
10
|
+
} | {
|
|
11
|
+
state: 'invalid';
|
|
12
|
+
value: string;
|
|
13
|
+
};
|
|
14
|
+
export declare function readCloudflarePlan(settings: SettingsConfig): PlanSetting;
|
|
15
|
+
export declare function entitlesCountryBlock(plan: CloudflarePlan): boolean;
|
|
16
|
+
export declare function entitlesDnsRecordTags(plan: CloudflarePlan): boolean;
|
|
17
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/rules/cloudflare/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAGnD,eAAO,MAAM,gBAAgB,oDAKnB,CAAC;AAEX,eAAO,MAAM,oBAAoB,uJACmH,CAAC;AAErJ,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE/D,MAAM,MAAM,WAAW,GACnB;IAAE,KAAK,EAAE,OAAO,CAAA;CAAE,GAClB;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,cAAc,CAAA;CAAE,GACxC;IAAE,KAAK,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAkBxC,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,cAAc,GAAG,WAAW,CAKxE;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAElE;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAEnE"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { lintofuSettings, objectSetting } from '../core/utils.js';
|
|
2
|
+
export const CLOUDFLARE_PLANS = [
|
|
3
|
+
'free',
|
|
4
|
+
'pro',
|
|
5
|
+
'business',
|
|
6
|
+
'enterprise',
|
|
7
|
+
];
|
|
8
|
+
export const INVALID_PLAN_MESSAGE = 'Unrecognized Cloudflare plan "{{value}}" in `settings.lintofu.cloudflare.plan`. Accepted values are `free`, `pro`, `business`, and `enterprise`.';
|
|
9
|
+
function isCloudflarePlan(value) {
|
|
10
|
+
return (typeof value === 'string' &&
|
|
11
|
+
CLOUDFLARE_PLANS.includes(value));
|
|
12
|
+
}
|
|
13
|
+
function describeSetting(value) {
|
|
14
|
+
if (typeof value === 'string')
|
|
15
|
+
return value;
|
|
16
|
+
if (typeof value === 'number' || typeof value === 'boolean') {
|
|
17
|
+
return String(value);
|
|
18
|
+
}
|
|
19
|
+
if (typeof value === 'object')
|
|
20
|
+
return JSON.stringify(value);
|
|
21
|
+
return typeof value;
|
|
22
|
+
}
|
|
23
|
+
export function readCloudflarePlan(settings) {
|
|
24
|
+
const plan = objectSetting(lintofuSettings(settings).cloudflare).plan;
|
|
25
|
+
if (plan === undefined)
|
|
26
|
+
return { state: 'unset' };
|
|
27
|
+
if (isCloudflarePlan(plan))
|
|
28
|
+
return { state: 'valid', plan };
|
|
29
|
+
return { state: 'invalid', value: describeSetting(plan) };
|
|
30
|
+
}
|
|
31
|
+
export function entitlesCountryBlock(plan) {
|
|
32
|
+
return plan === 'enterprise';
|
|
33
|
+
}
|
|
34
|
+
export function entitlesDnsRecordTags(plan) {
|
|
35
|
+
return plan !== 'free';
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/rules/cloudflare/utils.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAElE,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,MAAM;IACN,KAAK;IACL,UAAU;IACV,YAAY;CACJ,CAAC;AAEX,MAAM,CAAC,MAAM,oBAAoB,GAC/B,kJAAkJ,CAAC;AASrJ,SAAS,gBAAgB,CAAC,KAAc;IACtC,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;QACxB,gBAAsC,CAAC,QAAQ,CAAC,KAAK,CAAC,CACxD,CAAC;AACJ,CAAC;AAED,SAAS,eAAe,CAAC,KAAc;IACrC,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5C,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,SAAS,EAAE,CAAC;QAC5D,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;IACvB,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC5D,OAAO,OAAO,KAAK,CAAC;AACtB,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,QAAwB;IACzD,MAAM,IAAI,GAAG,aAAa,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC;IACtE,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;IAClD,IAAI,gBAAgB,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC5D,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC;AAC5D,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,IAAoB;IACvD,OAAO,IAAI,KAAK,YAAY,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,IAAoB;IACxD,OAAO,IAAI,KAAK,MAAM,CAAC;AACzB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"documented-outputs.d.ts","sourceRoot":"","sources":["../../../src/rules/core/documented-outputs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAG7D,QAAA,MAAM,IAAI,EAAE,sBAAsB,CAAC;IAAE,UAAU,EAAE,oBAAoB,CAAA;CAAE,CAoCtE,CAAC;AAEF,eAAe,IAAI,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { blockLabel, checkDescription } from './utils.js';
|
|
2
|
+
const rule = {
|
|
3
|
+
meta: {
|
|
4
|
+
type: 'problem',
|
|
5
|
+
docs: {
|
|
6
|
+
description: 'Require every `output` block to have a `description`.',
|
|
7
|
+
recommended: true,
|
|
8
|
+
severity: 'error',
|
|
9
|
+
},
|
|
10
|
+
messages: {
|
|
11
|
+
missingDescription: 'Output `{{name}}` is missing a `description` attribute.',
|
|
12
|
+
},
|
|
13
|
+
schema: [],
|
|
14
|
+
},
|
|
15
|
+
create(context) {
|
|
16
|
+
return {
|
|
17
|
+
Block(node) {
|
|
18
|
+
if (node.kind !== 'output')
|
|
19
|
+
return;
|
|
20
|
+
const label = blockLabel(node);
|
|
21
|
+
const check = checkDescription(node);
|
|
22
|
+
if (check.status === 'missing') {
|
|
23
|
+
context.report({
|
|
24
|
+
node,
|
|
25
|
+
messageId: 'missingDescription',
|
|
26
|
+
data: { name: label },
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
else if (check.status === 'empty') {
|
|
30
|
+
context.report({
|
|
31
|
+
node: check.attr,
|
|
32
|
+
messageId: 'missingDescription',
|
|
33
|
+
data: { name: label },
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
export default rule;
|
|
41
|
+
//# sourceMappingURL=documented-outputs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"documented-outputs.js","sourceRoot":"","sources":["../../../src/rules/core/documented-outputs.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAE1D,MAAM,IAAI,GAAiE;IACzE,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACJ,WAAW,EAAE,uDAAuD;YACpE,WAAW,EAAE,IAAI;YACjB,QAAQ,EAAE,OAAO;SAClB;QACD,QAAQ,EAAE;YACR,kBAAkB,EAChB,yDAAyD;SAC5D;QACD,MAAM,EAAE,EAAE;KACX;IACD,MAAM,CAAC,OAAO;QACZ,OAAO;YACL,KAAK,CAAC,IAAI;gBACR,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ;oBAAE,OAAO;gBACnC,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;gBAC/B,MAAM,KAAK,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;gBACrC,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;oBAC/B,OAAO,CAAC,MAAM,CAAC;wBACb,IAAI;wBACJ,SAAS,EAAE,oBAAoB;wBAC/B,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE;qBACtB,CAAC,CAAC;gBACL,CAAC;qBAAM,IAAI,KAAK,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC;oBACpC,OAAO,CAAC,MAAM,CAAC;wBACb,IAAI,EAAE,KAAK,CAAC,IAAI;wBAChB,SAAS,EAAE,oBAAoB;wBAC/B,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE;qBACtB,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,eAAe,IAAI,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"documented-variables.d.ts","sourceRoot":"","sources":["../../../src/rules/core/documented-variables.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAG7D,QAAA,MAAM,IAAI,EAAE,sBAAsB,CAAC;IAAE,UAAU,EAAE,oBAAoB,CAAA;CAAE,CAoCtE,CAAC;AAEF,eAAe,IAAI,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { blockLabel, checkDescription } from './utils.js';
|
|
2
|
+
const rule = {
|
|
3
|
+
meta: {
|
|
4
|
+
type: 'problem',
|
|
5
|
+
docs: {
|
|
6
|
+
description: 'Require every `variable` block to have a `description`.',
|
|
7
|
+
recommended: true,
|
|
8
|
+
severity: 'error',
|
|
9
|
+
},
|
|
10
|
+
messages: {
|
|
11
|
+
missingDescription: 'Variable `{{name}}` is missing a `description` attribute.',
|
|
12
|
+
},
|
|
13
|
+
schema: [],
|
|
14
|
+
},
|
|
15
|
+
create(context) {
|
|
16
|
+
return {
|
|
17
|
+
Block(node) {
|
|
18
|
+
if (node.kind !== 'variable')
|
|
19
|
+
return;
|
|
20
|
+
const label = blockLabel(node);
|
|
21
|
+
const check = checkDescription(node);
|
|
22
|
+
if (check.status === 'missing') {
|
|
23
|
+
context.report({
|
|
24
|
+
node,
|
|
25
|
+
messageId: 'missingDescription',
|
|
26
|
+
data: { name: label },
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
else if (check.status === 'empty') {
|
|
30
|
+
context.report({
|
|
31
|
+
node: check.attr,
|
|
32
|
+
messageId: 'missingDescription',
|
|
33
|
+
data: { name: label },
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
export default rule;
|
|
41
|
+
//# sourceMappingURL=documented-variables.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"documented-variables.js","sourceRoot":"","sources":["../../../src/rules/core/documented-variables.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAE1D,MAAM,IAAI,GAAiE;IACzE,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACJ,WAAW,EAAE,yDAAyD;YACtE,WAAW,EAAE,IAAI;YACjB,QAAQ,EAAE,OAAO;SAClB;QACD,QAAQ,EAAE;YACR,kBAAkB,EAChB,2DAA2D;SAC9D;QACD,MAAM,EAAE,EAAE;KACX;IACD,MAAM,CAAC,OAAO;QACZ,OAAO;YACL,KAAK,CAAC,IAAI;gBACR,IAAI,IAAI,CAAC,IAAI,KAAK,UAAU;oBAAE,OAAO;gBACrC,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;gBAC/B,MAAM,KAAK,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;gBACrC,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;oBAC/B,OAAO,CAAC,MAAM,CAAC;wBACb,IAAI;wBACJ,SAAS,EAAE,oBAAoB;wBAC/B,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE;qBACtB,CAAC,CAAC;gBACL,CAAC;qBAAM,IAAI,KAAK,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC;oBACpC,OAAO,CAAC,MAAM,CAAC;wBACb,IAAI,EAAE,KAAK,CAAC,IAAI;wBAChB,SAAS,EAAE,oBAAoB;wBAC/B,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE;qBACtB,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,eAAe,IAAI,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module-source-pinned.d.ts","sourceRoot":"","sources":["../../../src/rules/core/module-source-pinned.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAS7D,QAAA,MAAM,IAAI,EAAE,sBAAsB,CAAC;IAAE,UAAU,EAAE,gBAAgB,CAAA;CAAE,CAoClE,CAAC;AAEF,eAAe,IAAI,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { blockLabel, findAttribute, literalStringValue } from './utils.js';
|
|
2
|
+
function isPinnedSource(source, hasVersion) {
|
|
3
|
+
if (source.startsWith('./') || source.startsWith('../'))
|
|
4
|
+
return true;
|
|
5
|
+
if (source.includes('?ref='))
|
|
6
|
+
return true;
|
|
7
|
+
return hasVersion;
|
|
8
|
+
}
|
|
9
|
+
const rule = {
|
|
10
|
+
meta: {
|
|
11
|
+
type: 'problem',
|
|
12
|
+
docs: {
|
|
13
|
+
description: 'Require module sources to be pinned via `?ref=`, a `version` attribute, or a local path.',
|
|
14
|
+
recommended: true,
|
|
15
|
+
severity: 'error',
|
|
16
|
+
},
|
|
17
|
+
messages: {
|
|
18
|
+
unpinnedSource: 'Module `{{name}}` source is not pinned; add a `version` attribute or use a `?ref=` git URL.',
|
|
19
|
+
},
|
|
20
|
+
schema: [],
|
|
21
|
+
},
|
|
22
|
+
create(context) {
|
|
23
|
+
return {
|
|
24
|
+
Block(node) {
|
|
25
|
+
if (node.kind !== 'module')
|
|
26
|
+
return;
|
|
27
|
+
const sourceAttr = findAttribute(node.body.attributes, 'source');
|
|
28
|
+
if (!sourceAttr)
|
|
29
|
+
return;
|
|
30
|
+
const source = literalStringValue(sourceAttr.expression);
|
|
31
|
+
if (source === undefined)
|
|
32
|
+
return;
|
|
33
|
+
const hasVersion = !!findAttribute(node.body.attributes, 'version');
|
|
34
|
+
if (isPinnedSource(source, hasVersion))
|
|
35
|
+
return;
|
|
36
|
+
const label = blockLabel(node);
|
|
37
|
+
context.report({
|
|
38
|
+
node: sourceAttr,
|
|
39
|
+
messageId: 'unpinnedSource',
|
|
40
|
+
data: { name: label },
|
|
41
|
+
});
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
export default rule;
|
|
47
|
+
//# sourceMappingURL=module-source-pinned.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module-source-pinned.js","sourceRoot":"","sources":["../../../src/rules/core/module-source-pinned.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAE3E,SAAS,cAAc,CAAC,MAAc,EAAE,UAAmB;IACzD,IAAI,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACrE,IAAI,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC;QAAE,OAAO,IAAI,CAAC;IAC1C,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,MAAM,IAAI,GAA6D;IACrE,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACJ,WAAW,EACT,0FAA0F;YAC5F,WAAW,EAAE,IAAI;YACjB,QAAQ,EAAE,OAAO;SAClB;QACD,QAAQ,EAAE;YACR,cAAc,EACZ,6FAA6F;SAChG;QACD,MAAM,EAAE,EAAE;KACX;IACD,MAAM,CAAC,OAAO;QACZ,OAAO;YACL,KAAK,CAAC,IAAI;gBACR,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ;oBAAE,OAAO;gBACnC,MAAM,UAAU,GAAG,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;gBACjE,IAAI,CAAC,UAAU;oBAAE,OAAO;gBACxB,MAAM,MAAM,GAAG,kBAAkB,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;gBACzD,IAAI,MAAM,KAAK,SAAS;oBAAE,OAAO;gBAEjC,MAAM,UAAU,GAAG,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;gBACpE,IAAI,cAAc,CAAC,MAAM,EAAE,UAAU,CAAC;oBAAE,OAAO;gBAE/C,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;gBAC/B,OAAO,CAAC,MAAM,CAAC;oBACb,IAAI,EAAE,UAAU;oBAChB,SAAS,EAAE,gBAAgB;oBAC3B,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE;iBACtB,CAAC,CAAC;YACL,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,eAAe,IAAI,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-bool-as-count.d.ts","sourceRoot":"","sources":["../../../src/rules/core/no-bool-as-count.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AA6B7D,QAAA,MAAM,IAAI,EAAE,sBAAsB,CAAC;IAAE,UAAU,EAAE,aAAa,CAAA;CAAE,CA0C/D,CAAC;AAEF,eAAe,IAAI,CAAC"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { findAttribute } from './utils.js';
|
|
2
|
+
const COUNT_BLOCK_KINDS = new Set(['resource', 'data', 'module']);
|
|
3
|
+
const BOOL_BINARY_OPS = new Set([
|
|
4
|
+
'equal',
|
|
5
|
+
'notEqual',
|
|
6
|
+
'greaterThan',
|
|
7
|
+
'greaterThanOrEqual',
|
|
8
|
+
'lessThan',
|
|
9
|
+
'lessThanOrEqual',
|
|
10
|
+
'logicalAnd',
|
|
11
|
+
'logicalOr',
|
|
12
|
+
]);
|
|
13
|
+
function unwrapParens(expr) {
|
|
14
|
+
return expr.type === 'ParenthesesExpr' ? unwrapParens(expr.expression) : expr;
|
|
15
|
+
}
|
|
16
|
+
function isProvableBool(expr) {
|
|
17
|
+
const inner = unwrapParens(expr);
|
|
18
|
+
if (inner.type === 'LiteralValueExpr')
|
|
19
|
+
return typeof inner.value === 'boolean';
|
|
20
|
+
if (inner.type === 'UnaryOpExpr')
|
|
21
|
+
return inner.op === 'logicalNot';
|
|
22
|
+
if (inner.type === 'BinaryOpExpr')
|
|
23
|
+
return BOOL_BINARY_OPS.has(inner.op);
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
const rule = {
|
|
27
|
+
meta: {
|
|
28
|
+
type: 'problem',
|
|
29
|
+
fixable: 'code',
|
|
30
|
+
docs: {
|
|
31
|
+
description: 'Flag a `count` meta-argument set to a boolean; Terraform 0.12 removed bool-to-number coercion.',
|
|
32
|
+
recommended: true,
|
|
33
|
+
severity: 'error',
|
|
34
|
+
},
|
|
35
|
+
messages: {
|
|
36
|
+
boolAsCount: '`count` is set to a boolean value. Terraform 0.12 removed automatic bool-to-number coercion. Use a numeric conditional such as `count = var.enabled ? 1 : 0`.',
|
|
37
|
+
},
|
|
38
|
+
schema: [],
|
|
39
|
+
},
|
|
40
|
+
create(context) {
|
|
41
|
+
return {
|
|
42
|
+
Block(node) {
|
|
43
|
+
if (!COUNT_BLOCK_KINDS.has(node.kind))
|
|
44
|
+
return;
|
|
45
|
+
const count = findAttribute(node.body.attributes, 'count');
|
|
46
|
+
if (!count)
|
|
47
|
+
return;
|
|
48
|
+
const expr = count.expression;
|
|
49
|
+
if (!isProvableBool(expr))
|
|
50
|
+
return;
|
|
51
|
+
context.report({
|
|
52
|
+
node: expr,
|
|
53
|
+
messageId: 'boolAsCount',
|
|
54
|
+
fix: (fixer) => {
|
|
55
|
+
const inner = unwrapParens(expr);
|
|
56
|
+
if (inner.type === 'LiteralValueExpr' &&
|
|
57
|
+
typeof inner.value === 'boolean') {
|
|
58
|
+
return fixer.replaceText(expr, inner.value ? '1' : '0');
|
|
59
|
+
}
|
|
60
|
+
const text = context.sourceCode.getText(inner);
|
|
61
|
+
return fixer.replaceText(expr, `(${text}) ? 1 : 0`);
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
export default rule;
|
|
69
|
+
//# sourceMappingURL=no-bool-as-count.js.map
|