From cb515ed93775453099549226aae223f4dccf475b Mon Sep 17 00:00:00 2001 From: raj Date: Thu, 24 Apr 2025 13:52:10 +0530 Subject: [PATCH 1/4] Add cursor rule --- .cursor/rules/README.md | 39 +++++++++++++++++++ .cursor/rules/guide-cursor-rule.mdc | 10 +++++ .cursorrules | 11 ++++++ .github/workflows/markdown-lint-all | 18 +++++++++ .github/workflows/markdown-lint-pr-only.yml | 33 ++++++++++++++++ .markdownlint.json | 8 ++++ .markdownlint/custom-turbot-markdown-rules.js | 21 ++++++++++ 7 files changed, 140 insertions(+) create mode 100644 .cursor/rules/README.md create mode 100644 .cursor/rules/guide-cursor-rule.mdc create mode 100644 .cursorrules create mode 100644 .github/workflows/markdown-lint-all create mode 100644 .github/workflows/markdown-lint-pr-only.yml create mode 100644 .markdownlint.json create mode 100644 .markdownlint/custom-turbot-markdown-rules.js diff --git a/.cursor/rules/README.md b/.cursor/rules/README.md new file mode 100644 index 00000000..9ea12414 --- /dev/null +++ b/.cursor/rules/README.md @@ -0,0 +1,39 @@ +# Turbot Markdown Validator Pack + +## Includes + +- ✅ `.cursorrules` to guide Cursor AI generation +- ✅ Custom markdownlint rules to enforce doc format +- ✅ GitHub Action to validate PRs +- ✅ Works with pre-commit if needed + +## Setup + +1. Copy to your repo root: + - `.cursorrules` + - `.markdownlint.json` + - `.markdownlint/custom-turbot-markdown-rules.js` + - `.github/workflows/markdown-lint.yml` + +2. Install markdownlint locally (optional): +```bash +npm install -g markdownlint-cli2 +``` + +3. Run validation: +```bash +markdownlint-cli2 '**/*.md' +``` + +4. See GitHub PR checks run automatically + +**Note:** Here the workflow is designed to only capture the changed .md file. + + What `markdown-lint-pr-only` Does? + + - Runs only on Pull Requests to main + - Installs markdownlint-cli2 + - Detects .md files changed in the PR + - Lints only those files using your custom + rules + - Skips unrelated or legacy .md files \ No newline at end of file diff --git a/.cursor/rules/guide-cursor-rule.mdc b/.cursor/rules/guide-cursor-rule.mdc new file mode 100644 index 00000000..7200fffb --- /dev/null +++ b/.cursor/rules/guide-cursor-rule.mdc @@ -0,0 +1,10 @@ +--- +description: +globs: +alwaysApply: true +--- +"description": "All guides must use a standardized markdown structure with # title and ## sub-headers.", +"Use '# Title' followed by a high-level overview.", +"Include '## Prerequisites' if applicable.", +"Each major step should be a '## Step X: Description'.", +"End with '## Troubleshooting' and '## Next Steps' if relevant." diff --git a/.cursorrules b/.cursorrules new file mode 100644 index 00000000..77c813c3 --- /dev/null +++ b/.cursorrules @@ -0,0 +1,11 @@ +{ + "description": "Ensure all Turbot Guardrails docs follow a consistent markdown guide format.", + "rules": [ + "Start with YAML frontmatter containing 'title' and 'sidebar_label'.", + "Use a single '# Title' after frontmatter.", + "Include '## Prerequisites' section if applicable.", + "Steps must be formatted as '## Step X: ' in order.", + "Optionally include '## Troubleshooting' and '## Next Steps'.", + "Use Markdown image embeds and clear step-based headers." + ] +} \ No newline at end of file diff --git a/.github/workflows/markdown-lint-all b/.github/workflows/markdown-lint-all new file mode 100644 index 00000000..c449dd12 --- /dev/null +++ b/.github/workflows/markdown-lint-all @@ -0,0 +1,18 @@ +name: Markdown Lint + +on: + pull_request: + branches: [ main ] + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: 18 + - run: npm install -g markdownlint-cli2 + - name: Run markdownlint + run: markdownlint-cli2 '**/*.md' '#node_modules' \ No newline at end of file diff --git a/.github/workflows/markdown-lint-pr-only.yml b/.github/workflows/markdown-lint-pr-only.yml new file mode 100644 index 00000000..855b7b4c --- /dev/null +++ b/.github/workflows/markdown-lint-pr-only.yml @@ -0,0 +1,33 @@ +name: Markdown Lint + +on: + pull_request: + branches: [ main ] + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: 18 + + - name: Install markdownlint + run: npm install -g markdownlint-cli2 + + - name: Get changed markdown files + id: changed-files + uses: tj-actions/changed-files@v41 + + - name: Run markdownlint on changed files + if: steps.changed-files.outputs.any_changed == 'true' + run: | + echo "${{ steps.changed-files.outputs.all_changed_files }}" | tr ' ' '\n' | grep '\.md$' > changed-files.txt || true + if [ -s changed-files.txt ]; then + markdownlint-cli2 --config .markdownlint.json $(cat changed-files.txt) + else + echo "No markdown files changed." + fi diff --git a/.markdownlint.json b/.markdownlint.json new file mode 100644 index 00000000..e804b08c --- /dev/null +++ b/.markdownlint.json @@ -0,0 +1,8 @@ +{ + "default": true, + "MD025": false, + "MD013": false, + "custom-rules": [ + "./.markdownlint/custom-turbot-markdown-rules.js" + ] +} \ No newline at end of file diff --git a/.markdownlint/custom-turbot-markdown-rules.js b/.markdownlint/custom-turbot-markdown-rules.js new file mode 100644 index 00000000..fc743da5 --- /dev/null +++ b/.markdownlint/custom-turbot-markdown-rules.js @@ -0,0 +1,21 @@ +module.exports = { + names: ["TG002", "Turbot-Guide-Structure"], + description: "Validate markdown structure for Guardrails installation guides", + tags: ["structure", "guide", "guardrails"], + function: function(params, onError) { + const text = params.lines.join("\n"); + + const checks = [ + { name: "YAML frontmatter", regex: /^---[\s\S]*?---/, message: "Missing or incorrect YAML frontmatter" }, + { name: "Main title", regex: /^#\s+.+/, message: "Missing '# Title' header" }, + { name: "Prerequisites", regex: /##\s+Prerequisites/, message: "Missing '## Prerequisites' section" }, + { name: "Step headers", regex: /##\s+Step\s+\d+:\s+.+/, message: "No '## Step X:' formatted headers found" } + ]; + + checks.forEach(check => { + if (!check.regex.test(text)) { + onError({ lineNumber: 1, detail: check.message }); + } + }); + } +}; \ No newline at end of file From 6cdbd240a21e967bc54e0da2701d9776901ffd76 Mon Sep 17 00:00:00 2001 From: raj Date: Thu, 24 Apr 2025 17:31:03 +0530 Subject: [PATCH 2/4] Initial commit to check AI enabled validation --- docs/guides/aws/aws-sidebar.json | 10 ++- docs/guides/aws/controls/index.md | 12 ++++ .../aws/controls/s3-bucket-approved/index.md | 69 +++++++++++++++++++ 3 files changed, 89 insertions(+), 2 deletions(-) create mode 100644 docs/guides/aws/controls/index.md create mode 100644 docs/guides/aws/controls/s3-bucket-approved/index.md diff --git a/docs/guides/aws/aws-sidebar.json b/docs/guides/aws/aws-sidebar.json index 6b621aba..44f02dde 100644 --- a/docs/guides/aws/aws-sidebar.json +++ b/docs/guides/aws/aws-sidebar.json @@ -34,6 +34,12 @@ "items": ["guides/aws/permissions/user-mode"] }, "guides/aws/security-hub", - "guides/aws/decommission" + "guides/aws/decommission", + { + "type": "category", + "id": "controls", + "link": "guides/aws/controls", + "items": ["guides/aws/controls/s3-bucket-approved"] + } ] -} \ No newline at end of file +} diff --git a/docs/guides/aws/controls/index.md b/docs/guides/aws/controls/index.md new file mode 100644 index 00000000..0c1f0066 --- /dev/null +++ b/docs/guides/aws/controls/index.md @@ -0,0 +1,12 @@ +--- +title: AWS Controls +sidebar_label: Controls +--- + +# AWS Controls + +This section contains documentation for various AWS controls available in Turbot Guardrails. These controls help you manage and enforce policies across your AWS resources. + +## Available Controls + +- [S3 Bucket Approved](s3-bucket-approved) - Manage and enforce approval policies for S3 buckets \ No newline at end of file diff --git a/docs/guides/aws/controls/s3-bucket-approved/index.md b/docs/guides/aws/controls/s3-bucket-approved/index.md new file mode 100644 index 00000000..dbc524cb --- /dev/null +++ b/docs/guides/aws/controls/s3-bucket-approved/index.md @@ -0,0 +1,69 @@ +--- +title: AWS S3 Bucket Approved Control +sidebar_label: S3 Bucket Approved +--- + +# AWS S3 Bucket Approved Control + +The AWS S3 Bucket Approved control helps you manage and enforce approval policies for your S3 buckets. This control checks the status of defined Approved sub-policies and takes enforcement actions when buckets are not approved. + +## Prerequisites + +- Access to Turbot Guardrails with AWS integration configured +- Appropriate AWS permissions to manage S3 buckets +- Understanding of S3 bucket management in AWS + +## Step 1: Understanding the Control + +The Approved control evaluates S3 buckets against the following sub-policies: +- Usage policies +- Custom policies +- Region policies +- Budget policies + +When a bucket is not approved according to these policies, the control can: +- Raise alarms +- Take enforcement actions +- Delete unapproved buckets (if configured for new resources) + +## Step 2: Configuring the Control + +To configure the S3 Bucket Approved control: + +1. Navigate to the AWS > S3 > Bucket > Approved policy in your Turbot Guardrails workspace +2. Set the desired enforcement level: + - Skip + - Check + - Enforce + - Delete unapproved if new + +## Step 3: Setting Up Sub-policies + +Configure the following sub-policies to define approval criteria: + +1. **Usage Policies**: Define approved usage patterns +2. **Custom Policies**: Set custom approval rules +3. **Region Policies**: Specify approved regions +4. **Budget Policies**: Set budget constraints + +## Step 4: Monitoring and Enforcement + +Monitor the control through: +- Controls by Resource report +- Controls by Control Type report +- Alarms and notifications + +## Troubleshooting + +Common issues and solutions: +- **Control not triggering**: Verify AWS permissions and policy configurations +- **False positives**: Review and adjust sub-policy criteria +- **Enforcement not working**: Check enforcement level settings + +## Next Steps + +- Review other S3 bucket controls for comprehensive management +- Set up automated notifications for control violations +- Configure additional approval policies as needed + +For more information, visit the [AWS S3 Bucket Approved Control documentation](https://hub.guardrails.turbot.com/mods/aws/controls/aws-s3/bucketApproved). \ No newline at end of file From af3579b264eb9b7261f4f481e093bf78fc8aab89 Mon Sep 17 00:00:00 2001 From: raj Date: Thu, 24 Apr 2025 17:51:24 +0530 Subject: [PATCH 3/4] Updates validator to be more readable with purpose --- .markdownlint/custom-turbot-markdown-rules.js | 49 +++++++++++++++++-- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/.markdownlint/custom-turbot-markdown-rules.js b/.markdownlint/custom-turbot-markdown-rules.js index fc743da5..a876830a 100644 --- a/.markdownlint/custom-turbot-markdown-rules.js +++ b/.markdownlint/custom-turbot-markdown-rules.js @@ -1,20 +1,59 @@ +// Export a custom markdownlint rule object module.exports = { + // Unique rule identifier and a friendly name names: ["TG002", "Turbot-Guide-Structure"], + + // A short description of what the rule checks for description: "Validate markdown structure for Guardrails installation guides", + + // Tags help categorize or group related rules tags: ["structure", "guide", "guardrails"], + + // The main validation logic function: function(params, onError) { + // Join all lines into a single string to apply regex checks on full text const text = params.lines.join("\n"); + // Define a list of structural checks to apply const checks = [ - { name: "YAML frontmatter", regex: /^---[\s\S]*?---/, message: "Missing or incorrect YAML frontmatter" }, - { name: "Main title", regex: /^#\s+.+/, message: "Missing '# Title' header" }, - { name: "Prerequisites", regex: /##\s+Prerequisites/, message: "Missing '## Prerequisites' section" }, - { name: "Step headers", regex: /##\s+Step\s+\d+:\s+.+/, message: "No '## Step X:' formatted headers found" } + { + // Check that the guide starts with valid YAML frontmatter (between --- and ---) + name: "YAML frontmatter", + regex: /^---[\s\S]*?---/, + message: "Missing or incorrect YAML frontmatter" + }, + { + // Check for a single top-level title using markdown header syntax + // Example: # Install TED + name: "Main title", + regex: /^#\s+.+/, + message: "Missing '# Title' header" + }, + { + // Look for a section called '## Prerequisites' + // Helps ensure users know what to set up before proceeding + name: "Prerequisites", + regex: /##\s+Prerequisites/, + message: "Missing '## Prerequisites' section" + }, + { + // Validate that at least one step is present using the format: + // ## Step X: Description + name: "Step headers", + regex: /##\s+Step\s+\d+:\s+.+/, + message: "No '## Step X:' formatted headers found" + } ]; + // Loop through each check checks.forEach(check => { + // If the expected pattern is not found in the markdown, + // report an error using markdownlint's onError handler if (!check.regex.test(text)) { - onError({ lineNumber: 1, detail: check.message }); + onError({ + lineNumber: 1, // Simplified — we flag line 1 even though the issue could be anywhere + detail: check.message // Custom message defined per rule + }); } }); } From e24bdf5e1fafa628cf7834b6e85ae3c4dd8590f2 Mon Sep 17 00:00:00 2001 From: raj Date: Fri, 25 Apr 2025 10:55:40 +0530 Subject: [PATCH 4/4] Updates --- .cursor/rules/README.md | 16 +++++- .cursor/rules/guide-template.md | 53 +++++++++++++++++++ .markdownlint/custom-turbot-markdown-rules.js | 39 ++++++-------- 3 files changed, 85 insertions(+), 23 deletions(-) create mode 100644 .cursor/rules/guide-template.md diff --git a/.cursor/rules/README.md b/.cursor/rules/README.md index 9ea12414..2890566d 100644 --- a/.cursor/rules/README.md +++ b/.cursor/rules/README.md @@ -36,4 +36,18 @@ markdownlint-cli2 '**/*.md' - Detects .md files changed in the PR - Lints only those files using your custom rules - - Skips unrelated or legacy .md files \ No newline at end of file + - Skips unrelated or legacy .md files + + +## Purpose of `.markdownlint/custom-turbot-markdown-rules.js` + +(Draft structure) + +| **Required Section** | **Format Example** | **Purpose** | +|------------------------|-----------------------------------------------|-----------------------------------------------------------| +| YAML frontmatter | `--- title:... sidebar_label:... ---` | Metadata for the docs site and sidebar navigation | +| Title | `# Install TED` | Main title of the guide | +| Prerequisites | `## Prerequisites` | Setup and access requirements before starting the guide | +| At least one step | `## Step 1: Access AWS Console` | Structured step-by-step actions the user must perform | +| Next Steps | `## Next Steps` | Follow-up actions or related guides to explore | +| Troubleshooting | `## Troubleshooting` | Help section to resolve common errors or issues | diff --git a/.cursor/rules/guide-template.md b/.cursor/rules/guide-template.md new file mode 100644 index 00000000..76ba3c40 --- /dev/null +++ b/.cursor/rules/guide-template.md @@ -0,0 +1,53 @@ +--- +title: Example Guide Title +sidebar_label: Example Guide Title +--- + +# Example Guide Title + +In this guide, you will: +- [Briefly list what the user will achieve or learn] +- [Each bullet should be a practical outcome or goal] + +[Turbot Guardrails Enterprise Database (TED)](/guardrails/docs/reference/glossary#turbot-guardrails-enterprise-database-ted) is... + +## Prerequisites + +- [List any required AWS/Azure access, Turbot environment setup, permissions, etc.] +- [Link to docs or FAQs where relevant] + +## Step 1: [Start with an Actionable Step] + +Describe the first step clearly. Provide relevant screenshots if available. + +![Step 1 Screenshot](/images/docs/path-to-image.png) + +## Step 2: [Next Action Step] + +Same format here. + +## Step 3: [Another step] + +... + +## Step N: Review + +- [ ] Validate stack status is `CREATE_COMPLETE` +- [ ] Verify product status is `Available` +- [ ] Other post-install checks + +## Next Steps + +- Link to related guides +- Example: [Update TED](/guardrails/docs/runbooks/enterprise-install/update-ted) +- Example: [Architecture overview](/guardrails/docs/enterprise/architecture) + +## Troubleshooting + +| Issue | Description | Solution/Guide | +|------------------------|-----------------------------------------------------------------------------------------------|-----------------------------------------------------| +| Permissions error | User lacks IAM permission to modify stacks | [Admin Permissions](/guardrails/docs/...) | +| Installation stuck | Stack in `CREATE_IN_PROGRESS` for too long | Check CloudFormation Events | +| Product unavailable | No option to launch product after config | [Troubleshooting Deployment](/guardrails/docs/...) | + +> Need more help? [Open a Support Ticket](https://support.turbot.com) \ No newline at end of file diff --git a/.markdownlint/custom-turbot-markdown-rules.js b/.markdownlint/custom-turbot-markdown-rules.js index a876830a..39a1833a 100644 --- a/.markdownlint/custom-turbot-markdown-rules.js +++ b/.markdownlint/custom-turbot-markdown-rules.js @@ -1,58 +1,53 @@ -// Export a custom markdownlint rule object +// Export a markdownlint custom rule object module.exports = { - // Unique rule identifier and a friendly name + // Unique ID and name for the rule names: ["TG002", "Turbot-Guide-Structure"], - - // A short description of what the rule checks for description: "Validate markdown structure for Guardrails installation guides", - - // Tags help categorize or group related rules tags: ["structure", "guide", "guardrails"], - // The main validation logic function: function(params, onError) { - // Join all lines into a single string to apply regex checks on full text const text = params.lines.join("\n"); - // Define a list of structural checks to apply + // List of structural validations for the guide format const checks = [ { - // Check that the guide starts with valid YAML frontmatter (between --- and ---) name: "YAML frontmatter", regex: /^---[\s\S]*?---/, message: "Missing or incorrect YAML frontmatter" }, { - // Check for a single top-level title using markdown header syntax - // Example: # Install TED name: "Main title", regex: /^#\s+.+/, message: "Missing '# Title' header" }, { - // Look for a section called '## Prerequisites' - // Helps ensure users know what to set up before proceeding - name: "Prerequisites", + name: "Prerequisites section", regex: /##\s+Prerequisites/, message: "Missing '## Prerequisites' section" }, { - // Validate that at least one step is present using the format: - // ## Step X: Description name: "Step headers", regex: /##\s+Step\s+\d+:\s+.+/, message: "No '## Step X:' formatted headers found" + }, + { + name: "Next Steps section", + regex: /##\s+Next\s+Steps/, + message: "Missing '## Next Steps' section" + }, + { + name: "Troubleshooting section", + regex: /##\s+Troubleshooting/, + message: "Missing '## Troubleshooting' section" } ]; - // Loop through each check + // Run all checks and flag the document if any are missing checks.forEach(check => { - // If the expected pattern is not found in the markdown, - // report an error using markdownlint's onError handler if (!check.regex.test(text)) { onError({ - lineNumber: 1, // Simplified — we flag line 1 even though the issue could be anywhere - detail: check.message // Custom message defined per rule + lineNumber: 1, // Conservative reporting; could be improved to detect actual lines + detail: check.message }); } });