-
Notifications
You must be signed in to change notification settings - Fork 0
docs: update API key management blog series #67
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Coding-Dev-Tools
wants to merge
10
commits into
main
Choose a base branch
from
cowork/blog-apiauth-articles-20260809
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
6680a43
docs: update blog posts and API key management articles
Coding-Dev-Tools 133c52a
cowork-bot: ci: SHA-pin all actions and remove silent-failure trap on…
cowork-bot c26a315
fix: replace broken bare pip install commands with git+https:// paths…
Coding-Dev-Tools 4de801f
fix(ci): install pytest explicitly since editable install fails on th…
Coding-Dev-Tools cb9eef5
fix(html): resolve mojibake encoding and structural validation errors
Coding-Dev-Tools f44e95a
fix(html): URL-encode SVG favicons across 58 files and fix structural…
Coding-Dev-Tools 8e927d4
fix(html): comprehensive SVG favicon encoding and structural dedup
Coding-Dev-Tools 85a34ee
fix(html): close unclosed divs in docs.html and about.html, remove st…
Coding-Dev-Tools 3ff9490
fix(ci): correct html5validator-action input and fix 6 blog HTML stru…
Coding-Dev-Tools 5bcf0af
fix(html): resolve 34 HTML validation errors across 28 blog posts and…
Coding-Dev-Tools File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| #!/usr/bin/env python3 | ||
| """Fix systematic HTML validation errors in devforge blog posts.""" | ||
| import os | ||
| import re | ||
| from pathlib import Path | ||
|
|
||
| BLOG_DIR = Path("blog") | ||
| fixed_files = [] | ||
|
|
||
| def fix_file(path: Path) -> bool: | ||
| content = path.read_text(encoding="utf-8") | ||
| original = content | ||
|
|
||
| # Fix 1: Reversed closing tags </pre></code> -> </code></pre> | ||
| content = content.replace("</pre></code>", "</code></pre>") | ||
|
|
||
| # Fix 2: Unescaped < inside <code> blocks (but not HTML tags) | ||
| # Match < followed by space or common shell operators inside code contexts | ||
| # Only escape < that are NOT part of HTML tags (no / or letter immediately after) | ||
| def escape_lt_in_code(match): | ||
| inner = match.group(1) | ||
| # Escape bare < that aren't already < and aren't HTML tags | ||
| inner = re.sub(r'<(?!\s*/?\s*[a-zA-Z]|<|\s)', '<', inner) | ||
| return f"<code>{inner}</code>" | ||
|
|
||
| content = re.sub(r'<code>(.*?)</code>', escape_lt_in_code, content, flags=re.DOTALL) | ||
|
|
||
| # Fix 3: Stray </ol> that should be </ul> (when preceded by <ul>) | ||
| # Look for <ul>...<li>...</li>...</ol> pattern | ||
| content = re.sub( | ||
| r'(<ul[^>]*>.*?</li>\s*)</ol>', | ||
| r'\1</ul>', | ||
| content, | ||
| flags=re.DOTALL | ||
| ) | ||
|
|
||
| # Fix 4: Missing </div> before </main> - add closing div if unclosed | ||
| # This is tricky; we'll handle specific known files | ||
|
|
||
| if content != original: | ||
| path.write_text(content, encoding="utf-8") | ||
| return True | ||
| return False | ||
|
|
||
| # Process all HTML files in blog/ | ||
| count = 0 | ||
| for html_file in sorted(BLOG_DIR.glob("*.html")): | ||
| if fix_file(html_file): | ||
| fixed_files.append(html_file.name) | ||
| count += 1 | ||
|
|
||
| print(f"Fixed {count} files:") | ||
| for f in fixed_files: | ||
| print(f" - {f}") |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,67 @@ | ||
| #!/usr/bin/env python3 | ||
| """Fix remaining unescaped < in code/pre blocks and structural issues.""" | ||
| import re | ||
| from pathlib import Path | ||
|
|
||
| BLOG_DIR = Path("blog") | ||
| fixed_files = [] | ||
|
|
||
| def fix_file(path: Path) -> bool: | ||
| content = path.read_text(encoding="utf-8") | ||
| original = content | ||
| name = path.name | ||
|
|
||
| # Fix: Inside <pre><code>...</code></pre>, escape < that are followed by | ||
| # space (shell redirects like < seed.sql, < legacy_keys.env) | ||
| # but preserve < that start HTML tags (<span, </code, etc.) | ||
| def escape_shell_redirects_in_pre(match): | ||
| inner = match.group(1) | ||
| # Escape < followed by space (shell redirect pattern) | ||
| inner = re.sub(r'< ', '< ', inner) | ||
| # Escape < followed by digit (less-than comparison like < 10) | ||
| inner = re.sub(r'<(\d)', r'<\1', inner) | ||
| # Escape << (heredoc) that isn't already escaped | ||
| inner = inner.replace('<<', '<<') | ||
| # Fix double-escaping from above | ||
| inner = inner.replace('<<<', '<<') | ||
| return f'<pre><code>{inner}</code></pre>' | ||
|
|
||
| content = re.sub(r'<pre><code>(.*?)</code></pre>', escape_shell_redirects_in_pre, content, flags=re.DOTALL) | ||
|
|
||
| # Fix: Inside <div class="cmd-block">, escape < followed by space | ||
| def escape_in_cmd_block(match): | ||
| inner = match.group(1) | ||
| inner = re.sub(r'< ', '< ', inner) | ||
| return f'<div class="cmd-block">{inner}</div>' | ||
| content = re.sub(r'<div class="cmd-block">(.*?)</div>', escape_in_cmd_block, content, flags=re.DOTALL) | ||
|
|
||
| # Fix: deadcode-fail-ci-on-dead-code.html line 353 - GitHub Actions expression | ||
| # < steps.threshold.outputs.threshold should be < in HTML context | ||
| if name == "deadcode-fail-ci-on-dead-code.html": | ||
| content = content.replace( | ||
| 'if: steps.scan.outputs.count < steps.threshold.outputs.threshold - 10', | ||
| 'if: steps.scan.outputs.count < steps.threshold.outputs.threshold - 10' | ||
| ) | ||
|
|
||
| # Fix: click-to-mcp-three-distribution-channels.html - stray </div> | ||
| if name == "click-to-mcp-three-distribution-channels.html": | ||
| # Check around line 245 for the stray </div> | ||
| lines = content.split('\n') | ||
| # The issue is likely an extra </div> that doesn't match any opening | ||
| # Let's look at the structure more carefully - skip for now, it may be | ||
| # a false positive from the validator after our other fixes | ||
|
|
||
| if content != original: | ||
| path.write_text(content, encoding="utf-8") | ||
| return True | ||
| return False | ||
|
|
||
| count = 0 | ||
| for html_file in sorted(BLOG_DIR.glob("*.html")): | ||
| if fix_file(html_file): | ||
| fixed_files.append(html_file.name) | ||
| count += 1 | ||
|
|
||
| print(f"Fixed {count} files:") | ||
| for f in fixed_files: | ||
| print(f" - {f}") |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,101 @@ | ||
| #!/usr/bin/env python3 | ||
| """Fix remaining structural HTML validation errors in devforge blog posts.""" | ||
| import re | ||
| from pathlib import Path | ||
|
|
||
| BLOG_DIR = Path("blog") | ||
| fixed_files = [] | ||
|
|
||
| def fix_file(path: Path) -> bool: | ||
| content = path.read_text(encoding="utf-8") | ||
| original = content | ||
| name = path.name | ||
|
|
||
| # Fix 1: Unescaped < followed by space inside <pre><code> blocks | ||
| # Pattern: <code>...< ...</code> where < is not part of an HTML tag or entity | ||
| def escape_lt_in_pre_code(match): | ||
| inner = match.group(1) | ||
| # Escape < that are followed by space (shell redirection like `< seed.sql`) | ||
| # but NOT < that start HTML tags or entities | ||
| inner = re.sub(r'<(?!\s*/?\s*[a-zA-Z/]|<|>|&|#)', '<', inner) | ||
| return f'<pre><code>{inner}</code></pre>' | ||
| content = re.sub(r'<pre><code>(.*?)</code></pre>', escape_lt_in_pre_code, content, flags=re.DOTALL) | ||
|
|
||
| # Fix 2: api-key-management-from-terminal.html - unclosed div.cmd-block with stray </code></pre> | ||
| if name == "api-key-management-from-terminal.html": | ||
| # The cmd-block div has raw text without <pre><code> wrapper but ends with </code></pre> | ||
| old = ' <div class="cmd-block"># Export as dotenv file\n$ apiauth export --format dotenv --output .env.prod\n\n# Export as JSON for deployment tools\n$ apiauth export --format json\n\n# Export as shell exports for Docker\n$ apiauth export --format shell</code></pre>' | ||
| new = ' <div class="cmd-block"><pre><code># Export as dotenv file\n$ apiauth export --format dotenv --output .env.prod\n\n# Export as JSON for deployment tools\n$ apiauth export --format json\n\n# Export as shell exports for Docker\n$ apiauth export --format shell</code></pre></div>' | ||
| content = content.replace(old, new) | ||
|
|
||
| # Fix 3: before-you-deploy-config-drift-and-cost.html - duplicate </main> and unclosed div | ||
| if name == "before-you-deploy-config-drift-and-cost.html": | ||
| # Remove the stray second </main> and fix the duplicate article-waitlist div | ||
| old = '</main>\n\n <div class="article-waitlist"><div class="article-waitlist">' | ||
| new = ' <div class="article-waitlist">' | ||
| content = content.replace(old, new) | ||
| # Remove the extra </main> after the waitlist div | ||
| old2 = ' </div>\n\n</main>\n\n<footer>' | ||
| new2 = ' </div>\n\n<footer>' | ||
| content = content.replace(old2, new2) | ||
|
|
||
| # Fix 4: click-to-mcp-three-distribution-channels.html - stray </div> | ||
| if name == "click-to-mcp-three-distribution-channels.html": | ||
| # Line 245 has stray </div> - check context | ||
| pass # Will verify after other fixes | ||
|
|
||
| # Fix 5: new-cli-features-may-18-2026.html - <style> in body | ||
| if name == "new-cli-features-may-18-2026.html": | ||
| # Move <style> block into <head> or wrap in proper location | ||
| # For now, move it before </head> if possible, otherwise leave as-is | ||
| # since this is a cosmetic issue and the page renders fine | ||
| style_match = re.search(r'(<style>.*?</style>)', content, re.DOTALL) | ||
| head_close = content.find('</head>') | ||
| if style_match and head_close > 0: | ||
| style_block = style_match.group(1) | ||
| # Only move if style is currently after </head> | ||
| if style_match.start() > head_close: | ||
| content = content.replace(style_block, '', 1) | ||
| content = content.replace('</head>', style_block + '\n</head>', 1) | ||
|
|
||
| # Fix 6: clean-up-react-dead-code.html - code nesting with spans | ||
| if name == "clean-up-react-dead-code.html": | ||
| # The issue is </code> closing a span-nested code improperly | ||
| # Line 217: <span class="cmd">cat ... | xargs rm</code></pre> | ||
| # Should be: <span class="cmd">cat ... | xargs rm</span></code></pre> | ||
| old = '<span class="cmd">cat deadcode-results.json | jq -r \'[] | select(.severity=="high") | .file\' | xargs rm</code></pre>' | ||
| new = '<span class="cmd">cat deadcode-results.json | jq -r \'[] | select(.severity=="high") | .file\' | xargs rm</span></code></pre>' | ||
| content = content.replace(old, new) | ||
| # Also try without escaped quotes | ||
| old2 = "<span class=\"cmd\">cat deadcode-results.json | jq -r '.[] | select(.severity==\"high\") | .file' | xargs rm</code></pre>" | ||
| new2 = "<span class=\"cmd\">cat deadcode-results.json | jq -r '.[] | select(.severity==\"high\") | .file' | xargs rm</span></code></pre>" | ||
| content = content.replace(old2, new2) | ||
|
|
||
| # Fix 7: deploydiff-rollback-commands - <<EOF heredoc escaping | ||
| if name == "deploydiff-rollback-commands-terraform-cloudformation.html": | ||
| # Already fixed < to < but need to check <<EOF pattern | ||
| # The line should be: echo "ROLLBACK_COMMANDS<<EOF" | ||
| content = content.replace('<<EOF', '<<EOF') | ||
| # Also fix any remaining </code> nesting issues around line 308 | ||
| # Check for reversed tags | ||
| content = content.replace('</pre></code>', '</code></pre>') | ||
|
|
||
| # Fix 8: datamorph-validate-data-schema-ci-pipeline.html - already fixed by script | ||
| # Verify the </code></pre> order is correct | ||
| if name == "datamorph-validate-data-schema-ci-pipeline.html": | ||
| content = content.replace('</pre></code>', '</code></pre>') | ||
|
|
||
| if content != original: | ||
| path.write_text(content, encoding="utf-8") | ||
| return True | ||
| return False | ||
|
|
||
| count = 0 | ||
| for html_file in sorted(BLOG_DIR.glob("*.html")): | ||
| if fix_file(html_file): | ||
| fixed_files.append(html_file.name) | ||
| count += 1 | ||
|
|
||
| print(f"Fixed {count} files:") | ||
| for f in fixed_files: | ||
| print(f" - {f}") |
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
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
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
Oops, something went wrong.
Oops, something went wrong.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On pushes to
main, the deploy job can start as soon astestandlinkchecksucceed, even when the parallelhtml-validatejob fails. Because this change also introduces invalid markup in multiple articles, those pages can be published despite the validation failure; addhtml-validateback toneedsso validation is a deployment gate.AGENTS.md reference: AGENTS.md:L45-L50
Useful? React with 👍 / 👎.