AI 资讯
🚀 Calling all DevOps, SRE, and Platform Engineers! Let’s build the future of AI for DevOps together.
Over the last few years, I've been exploring AI agents, and one thing became obvious. There are hundreds of AI agents available today, but almost all of them are general-purpose. They can answer questions, write code, or browse the web, but very few truly understand the day-to-day challenges of running production infrastructure. As someone who has spent years working in DevOps, I wanted something different. That's why I built DevOps Open Agent, an open-source, self-hosted AI platform designed specifically for DevOps engineers, SREs, and Platform teams. Today, the project includes: ✅ Kubernetes Debugging Agent for AI-assisted cluster troubleshooting ✅ AWS DevOps Agent for investigating infrastructure issues ✅ Cloud Cost Detector to identify optimization opportunities ✅ GitHub PR Reviewer with DevOps-focused code reviews ✅ Slack, Microsoft Teams, and PagerDuty integrations ✅ MCP support for connecting external tools and services ✅ Support for multiple LLM providers including OpenAI, Anthropic, Gemini, OpenRouter, and Ollama But this is just the beginning. There is so much more we can build together: ✔️ Better Kubernetes diagnostics ✔️ Smarter AWS investigations ✔️ Terraform and Infrastructure-as-Code analysis ✔️ Observability integrations ✔️ Performance debugging ✔️ Security analysis ✔️ Historical investigation memory And many more AI-powered workflows for production engineering If you're passionate about DevOps, SRE, Platform Engineering, or Generative AI, I'd love to have you involved. Whether you contribute code, improve documentation, report bugs, review pull requests, or suggest new ideas, every contribution helps move the project forward. ⭐ Give the repository a star 🍴 Fork the project 🚀 Pick an issue and submit a pull request If you've been looking for an opportunity to work at the intersection of DevOps and AI, this is it. Let's build the open-source AI platform that every DevOps engineer wishes existed. 🔗 Repository: https://github.com/ideaweaver-ai/devops-op
AI 资讯
Designing an Async Image API Client That Does Not Lie About Completion
Image generation is where a seemingly simple API client starts to accumulate production bugs. A request may finish inline for one model, return a task for another, or take a longer path when the input includes edits and uploaded files. Treating every successful HTTP response as a completed image is the fastest way to ship broken retry logic and incorrect user-facing status. This post adapts the TokenLab article TokenLab Async Image Generation Tasks for Production Apps . The canonical article contains the full implementation discussion; this version focuses on the contract decisions that matter when building an integration. The response is a delivery decision, not just a payload An image endpoint can return either a completed representation or an asynchronous task. The client should inspect the response envelope and normalize the delivery mode before it touches application state: type Delivery = | { mode : " sync " ; terminal : true } | { mode : " async " ; task_id : string ; status : string ; terminal : false }; The important invariant is that mode and terminal state come from the API contract. Do not infer completion from a missing progress field, a truthy data property, or a fast response time. Progress is useful when present, but it is not the completion signal. Poll by task identity, not by the original request When the server returns an async task, persist the task ID and the provider-neutral status. A worker can then poll the task endpoint with bounded backoff: async function waitForTask ( id : string ) { for ( let attempt = 0 ; attempt < 60 ; attempt += 1 ) { const task = await getTaskStatus ( id ); if ( task . status === " succeeded " ) return task . result ; if ([ " failed " , " cancelled " , " expired " ]. includes ( task . status )) { throw new Error ( `Media task ${ id } ended as ${ task . status } ` ); } await sleep ( Math . min ( 1000 * 2 ** Math . min ( attempt , 5 ), 30 _000 )); } throw new Error ( `Media task ${ id } exceeded the polling budget` );
AI 资讯
How to clone a Keycloak realm on the same instance (fixing "duplicate key value violates unique constraint")
If you've ever tried to duplicate a Keycloak realm on the same server — say, to spin up a myrealm-dev realm alongside your existing myrealm — you've probably hit this wall: Export the realm from the Admin Console ( Realm settings → Action → Partial export , with clients and groups/roles included). Rename it in a text editor, or in the import dialog's "realm name" field. Import it back into the same Keycloak instance. Watch it fail with: ERROR: duplicate key value violates unique constraint "constraint_a" Detail: Key (id)=(51e1a26d-c24f-4454-9a34-708f1fc14917) already exists. Why this happens A realm export isn't just configuration — it's a snapshot of database rows. Every role, client, user, protocol mapper, component, and authentication flow in the export carries the same internal UUID it has in the live database. Renaming the realm field changes what the realm is called , but it does nothing to the dozens (often hundreds) of UUIDs referenced throughout the file. Import that JSON into the instance it came from, and Keycloak tries to insert rows whose primary keys already exist. Every single one collides. This is a known limitation, tracked upstream as keycloak/keycloak#24770 . Keycloak's exporter was never designed to produce an import-anywhere-including-here artifact — it assumes you're moving the realm to a different instance (dev → staging → prod), where the UUID space is independent. The manual fix (and why it doesn't scale) In principle you can fix this by hand: open the export JSON, find every UUID, and replace it with a fresh one, while keeping track of which old UUID maps to which new UUID so that references between objects (a role's containerId , a client's serviceAccountClientId , a flow's execution list) still point at the right thing after the rewrite. For a small realm with a handful of clients this is tedious but doable in an editor with careful find-and-replace. For a realm with custom roles, several clients, an identity provider, and a full set of a
AI 资讯
Docker Volumes vs Bind Mounts: Where Your Data Actually Lives
A container's writable layer feels like a filesystem, and that's exactly the trap. Write a database into it, remove the container, and the data is gone — no warning, no recovery. If you want anything to survive docker rm , it has to live outside the container, and Docker gives you three ways to do that: named volumes, bind mounts, and tmpfs. Knowing which one to reach for is most of the battle. Why the writable layer betrays you Every running container gets a thin read-write layer stacked on top of its image layers. It looks persistent because you can docker exec in and see your files. But that layer is bound to the container's lifecycle. docker run --name scratch alpine sh -c 'echo hello > /data.txt; cat /data.txt' # hello docker rm scratch # the layer — and /data.txt — no longer exists There's no "oops." The writable layer is discarded with the container. Persistence is not a default you get; it's a decision you make. That decision is a volume, a bind mount, or tmpfs. Named volumes: the default for state A named volume is storage that Docker creates and manages for you. You give it a name, Docker keeps the actual bytes under its own directory, and you never have to care where that is. docker volume create pgdata docker run -d --name db \ --mount type = volume,source = pgdata,target = /var/lib/postgresql/data \ postgres:16 The container writes to /var/lib/postgresql/data , but those bytes land in a Docker-managed location on the host. Remove and recreate the container against the same volume and the data is still there. docker rm -f db docker run -d --name db \ --mount type = volume,source = pgdata,target = /var/lib/postgresql/data \ postgres:16 # same data, new container Where do the bytes actually live? Under Docker's data root, typically /var/lib/docker/volumes/<name>/_data : docker volume inspect pgdata --format '{{ .Mountpoint }}' # /var/lib/docker/volumes/pgdata/_data The point is that you're not supposed to reach into that path directly — Docker owns it. You
AI 资讯
n8n review: I automated 12 saas.pet workflows with it in 6 months
n8n is the open-source workflow automation tool that competes with Zapier and Make. I have been running it for saas.pet's content pipeline for 6 months. Here is my honest take on self-hosting n8n versus paying Zapier, and whether it is worth the hassle. What n8n does that Zapier cannot n8n is an open-source workflow automation platform with 400+ built-in integrations. You connect nodes on a visual canvas: when X happens in one app, do Y in another. The killer difference from Zapier: you control where it runs. Self-host on a $5/month VPS or run on n8n Cloud at $20/month. No per-task pricing, no 'you hit your zap limit' emails. For high-volume workflows, the cost difference is dramatic. I run n8n on the same $6/month HK server that hosts my proxy. 12 workflows handle saas.pet's entire content pipeline: daily data fetch from GitHub Trending API, transform JSON, write to data files, trigger build, push to git, notify me on Telegram. The same workflows on Zapier would cost $73.50/month (Professional plan with 2,000 tasks). On n8n, $6/month for the server plus $0 for the software. The self-hosting overhead is real—updates, SSL certs, monitoring—but for 12+ active workflows, the savings are $800+/year. If you only have 2-3 simple zaps, stay on Zapier's free tier. If you have 5+ workflows with volume, n8n pays for the hosting in month 1. My 6-month setup for saas.pet I run n8n in Docker on the HK server. The initial setup: install Docker, pull n8n image, configure nginx reverse proxy, set up SSL via Certbot. That took about 2 hours the first time. Now I can deploy n8n in 15 minutes on a fresh server. The 12 workflows: (1) Daily GitHub trending fetch via saas.pet/api/trending, (2) data transform to unified JSON, (3) write to data/YYYY-MM-DD.json, (4) trigger build-ci.mjs, (5) git add + commit + push, (6) Telegram notification with commit SHA, (7) weekly sitemap health check, (8) monthly backup of reviews/ JSONs to S3, (9) uptime ping every 15 minutes, (10) DNS health check,
AI 资讯
Building a Fully Automated Facebook Post Scheduler using Node.js and GitHub Actions
How I Built a Zero-Cost Facebook Auto-Poster Using Node.js and GitHub Actions Automating social media management can save hours of manual work. In this guide, I will show you how to build a fully automated, production-ready system that posts daily motivational quotes with images to a Facebook Page— completely for free , running on autopilot via GitHub Actions. We will also tackle a major pain point: resolving Meta's strict token expiration and permission structures by dynamically fetching a Page Access Token using a Meta Business System User, the officially recommended way for secure automation. 🛠️ Prerequisites Before diving into the code, make sure you have: A Facebook Page A Meta Developer Account A Meta Business Suite (Business Portfolio) A GitHub Account Basic knowledge of Node.js 🎯 Step 1: Configuring Meta Architecture for Secure Automation Meta has deprecated direct publish_actions for user tokens, making automated image uploads tricky. The professional way to solve this is by using a System User bound to a Business Portfolio . 1. Create a Meta App Go to the Meta for Developers dashboard. Create a new app, choose Business and pages as the category, and give it a clean name. 2. Link your Facebook Page Inside your App Dashboard, navigate to App Settings -> Advanced . Scroll down to the App Page section and select your target Facebook Page to link it. 3. Setup a System User Go to your Meta Business Settings ( business.facebook.com/settings ). Under Users , click on System Users and create an Admin System User (e.g., Ttp-penguin ). Click Assign Assets , select your Facebook Page, and turn on the Full Control (Everything) toggle. 4. Generate the Permanent Token Click Generate Token for that System User and select your app. Explicitly check these 3 essential scopes : pages_manage_posts pages_read_engagement pages_show_list Copy the generated token ( EAak2B... ). Save this safely —this token acts as our master key! 💻 Step 2: Writing the Automation Script We will wri
AI 资讯
Why Your Application Needs Observability: Building a Self-Hosted Observability Pipeline with the LGTM Stack (Loki, Grafana, Tempo, Mimir)
Understanding Observability with the LGTM Stack From "what happened last night?" to "here's exactly what happened and why" — in under 5 minutes Table of Contents Introduction What Is Observability? The Three Pillars of Observability Metrics Logs Traces Why You Need All Three Together The LGTM Stack Architecture: How It All Fits Together OpenTelemetry: The Instrumentation Standard The OTel Collector: The Brain of the Pipeline Loki: Log Aggregation Tempo: Distributed Tracing Mimir: Metrics at Scale Grafana: Connecting the Dots Conclusion Introduction Let me tell you a story that probably sounds familiar. It's 2 AM on a Sunday. Your API is slow. Users are complaining. But you're not at your desk — you're in a Sleeping, or just living your life. You have no idea it's even happening. The next morning you walk into the office and your boss meets you at the door. "Hey, the API was really slow yesterday around 2 AM. What happened?" And you're stuck. Completely stuck. You pull up the server logs — it's a wall of unformatted text. Maybe the issue already fixed itself. Maybe the container restarted overnight and the logs are gone. You weren't there, and your system left no trail. So you say the thing every developer dreads saying: "I don't know. I'll look into it." Now imagine the exact same situation — but this time you have observability set up. You open your dashboard, set the time range to yesterday 2 AM, and within two minutes you can see everything. Response times spiked to 4 seconds. The database connection pool got exhausted. And it started the exact moment a scheduled batch job kicked off and hammered the DB with hundreds of queries at once. You have a graph. You have traces. You have the exact log line that caused it. You walk back to your boss with your laptop: "Here's what happened and here's the fix." That's observability. Your system tells its own story — even when you're not watching. That's what this blog is about. I'll walk you through what observability actua
AI 资讯
Linux Foundation Launches Akrites to Protect Critical Open Source Software from AI-Powered Threats
The Linux Foundation has launched Akrites, a new industry-wide initiative aimed at defending the world's most critical open source software against a rapidly evolving generation of AI-enabled cyber threats. By Craig Risi
AI 资讯
GitHub Copilot CLI Gets Tabs and No-Config-File Tool Setup in Redesigned Terminal UI
GitHub has made the redesigned GitHub Copilot CLI terminal interface generally available. It adds a tabbed layout for sessions, gists, issues, and pull requests; an in-session, form-driven setup for MCP servers, skills, and plugins that avoids hand-editing config files; and a cleaner, theme-aware, more accessible UI with screen reader support. By Mark Silvester
AI 资讯
# Reflection – Week 2
" Shifting from Prompt Engineering to Infrastructure Orchestration " Week 2 was a mix of excitement, curiosity, and a little bit of frustration. I learned a lot of new concepts, but I also realized that the best way to understand them is by actually trying them out. Reading or watching tutorials helps, but experimenting with the tools made everything click for me. One of the topics I enjoyed learning about was Claude Code. Before this week, I mainly thought of AI as something that answers questions or helps write content. Seeing how Claude can assist with coding, debugging, and understanding projects made me see it differently. It feels less like a search engine and more like someone you can work with while building something. That really changed how I think about using AI in development. Another interesting topic was Skills. I liked the idea that you can give an LLM specific skills so it behaves more like a specialist instead of a general assistant. It made me realize that the quality of the output doesn't only depend on the model itself, but also on how you guide it and what tools or skills you give it. That was something I hadn't really thought about before, and I can already see how useful it could be for different types of projects. I also learned about Subagents, which was a new concept for me. At first, I didn't really understand why you would need multiple agents instead of just asking one AI to do everything. But after learning more about it, I started to see the benefit. Having different agents focus on different tasks seems like a much cleaner and more organized way to work, especially for bigger projects. The biggest challenge I faced this week was running out of tokens while practicing. It happened a few times, and honestly, it was a little annoying because I would be in the middle of exploring an idea and suddenly had to stop. Even though it was frustrating, it also made me think more carefully about how I write prompts and how I use my conversations.
AI 资讯
Improve WordPress Server Response Time by Optimizing Apache and Nginx Configuration
One of the most important performance metrics for a WordPress website is Server Response Time, commonly measured as Time to First Byte (TTFB). While caching plugins like WP Rocket significantly improve performance, many server configurations still route every request through PHP before serving the cached page. In reality, cached HTML files can be delivered directly by the web server (Apache or Nginx), completely bypassing PHP and WordPress. This approach reduces CPU usage, lowers the PHP-FPM workload, and improves overall server response time. This guide explains how to optimize both Apache (.htaccess) and Nginx so they can serve WP Rocket's static HTML cache directly. Why Is This Optimization Important? By default, a typical WordPress request follows this flow: Visitor │ ▼ Apache/Nginx │ ▼ PHP │ ▼ WordPress │ ▼ WP Rocket Cache │ ▼ HTML Response Even when a page has already been cached, the request still passes through PHP before the cached content is returned. With the following configuration, the request flow becomes: Visitor │ ▼ Apache/Nginx │ ▼ WP Rocket HTML Cache │ ▼ HTML Response PHP and WordPress are only executed when a cached file does not exist. Benefits Lower Time to First Byte (TTFB) Reduced CPU usage Less PHP-FPM processing Better performance during traffic spikes Ideal for VPS and dedicated servers Improved scalability with minimal configuration changes Apache (.htaccess) Optimization If your server runs Apache, insert the following block inside the WordPress rewrite section, immediately after: RewriteBase / and before: RewriteRule ^index\.php$ - [L] The resulting configuration should look like this: # BEGIN WordPress # Die Anweisungen (Zeilen) zwischen „BEGIN WordPress“ und „END WordPress“ sind # dynamisch generiert und sollten nur über WordPress-Filter geändert werden. # Alle Änderungen an den Anweisungen zwischen diesen Markierungen werden überschrieben. < IfModule mod_rewrite.c > RewriteEngine On RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Autho
开发者
Deploy a Dockerfile on Vercel
Yes, you heard it right, you can now run a Dockerfile on Vercel. Vercel was the go-to place where...
AI 资讯
Adopting Terraform Ephemeral Resources
In version 1.11, HashiCorp introduced Terraform Ephemeral resources and write-only attributes to allow for root configs that do not store secrets in the Terraform statefile. But many users ask about how they can adopt ephemerals. This blog attempts to lay out the ways secrets can be stored in state and how you should update your configurations to remove those secrets. Note: For a primer on ephemerals ( see this blog post ). Scenarios to consider: Data sources that fetch a static secret Resources that receive a secret Resources that generate a dynamic a secret Resources that fetch generated secrets to store in another 3rd party system Scenario 1: Data sources with static secrets Ephemeral resources can often be a drop-in replacement for data sources pulling static values: data "vault_kv_secret_v2" "static_kv" { mount = "kvv2" name = "my_password" } ephemeral "vault_kv_secret_v2" "static_kv" { mount = "kvv2" name = "my_password" } However, using these values has 1 specific difference. The attributes on a ephemeral resource are considered ephemeral and can only be used as ephemeral arguments. That means 2 places: Provider blocks Provider blocks are considered ephemeral, so ephemeral resources may populate arguments: provider "example" { password = tostring ( ephemeral . vault_kv_secret_v2 . static_kv . data . password ) } Write-only arguments Write-only arguments are special arguments that require the ephemeral taint for values: resource "aws_db_instance" "example" { ... password_wo = tostring ( ephemeral . vault_kv_secret_v2 . static_kv . data . password ) } If the resource you wish to pass a value to does not have an available ephemeral, open an issue with that provider. You can reference: this blog post this agent skill Scenario 2: Resources that receive a static secret Without duplicating to the section above, write-only arguments are a way to get secrets out of state. Above has guidance if the secret value comes from a data source, but what if its from a variable?
AI 资讯
How One Log File Turned Into Five Context Switches
The issue was not the tools. It was opening five of them before deciding what the log file was for. The log file was already on the screen. A remote Windows workstation had failed a desktop build, and the relevant file was sitting in a local app directory, something like: C:\Users\<user>\AppData\Local\<app>\logs\build.log The remote session was working. The error was visible. The next step seemed small: get the log back to the local laptop, open it in a familiar editor, compare it with the issue notes, and pull out the part that mattered. That should have been a 30-second task. Instead, it turned into five context switches. The first context was the remote session The remote desktop session made sense. The build failed on that machine, the app was installed there, and the log path was easier to find visually than by guessing from memory. So far, nothing was wrong. The file was selected. The timestamp matched the failed run. The log looked useful. It probably had the stack trace, the missing dependency path, or the configuration mismatch that explained the build failure. Then came the small but surprisingly annoying question: How should this file leave the remote machine? That is where the workflow started to wobble. The second context was chat The first instinct in many teams is chat. Drop the file into a message to yourself, a teammate, or the debugging thread. It is fast, already open, and keeps the file near the conversation. For some files, that is the right move. A screenshot, a short error snippet, or a quick “does this look familiar?” artifact belongs naturally in the discussion. But a full log file is not always a chat artifact. If it goes into chat, will anyone know later whether it was the first failing run or the second? Will it be obvious which remote machine produced it? Will the file still be easy to find after the thread moves on? Chat was not wrong. It was just not clearly the right home for this specific file. So the workflow moved on. The third con
AI 资讯
Linux compliance checks with Sparrow plugin
Sparrow is Raku automation framework comes with useful plugins people can use to automate infrastructure. Scc plugin allows to check Linux essential configuration files for security compliance. Here some examples: Sysctl $ sudo sysctl -a | s6 --plg-run scc@check = sysctl 12:24:07 :: [task] - run plg scc@check=sysctl 12:24:07 :: [task] - run [scc], thing: scc@check=sysctl [task run: task.bash - scc] [task stdout] 12:24:08 :: abi.cp15_barrier = 1 12:24:08 :: abi.setend = 1 12:24:08 :: abi.swp = 0 12:24:08 :: abi.tagged_addr_disabled = 0 12:24:08 :: debug.exception-trace = 0 12:24:08 :: dev.cdrom.autoclose = 1 12:24:08 :: dev.cdrom.autoeject = 0 12:24:08 :: dev.cdrom.check_media = 0 12:24:08 :: dev.cdrom.debug = 0 12:24:08 :: dev.cdrom.info = CD-ROM information, Id: cdrom.c 3.20 2003/12/17 12:24:08 :: dev.cdrom.info = 12:24:08 :: dev.cdrom.info = drive name: 12:24:08 :: dev.cdrom.info = drive speed: 12:24:08 :: dev.cdrom.info = drive # of slots: 12:24:08 :: dev.cdrom.info = Can close tray: 12:24:08 :: dev.cdrom.info = Can open tray: 12:24:08 :: dev.cdrom.info = Can lock tray: 12:24:08 :: dev.cdrom.info = Can change speed: 12:24:08 :: dev.cdrom.info = Can select disk: 12:24:08 :: dev.cdrom.info = Can read multisession: 12:24:08 :: dev.cdrom.info = Can read MCN: 12:24:08 :: dev.cdrom.info = Reports media changed: 12:24:08 :: dev.cdrom.info = Can play audio: 12:24:08 :: dev.cdrom.info = Can write CD-R: 12:24:08 :: dev.cdrom.info = Can write CD-RW: 12:24:08 :: dev.cdrom.info = Can read DVD: 12:24:08 :: dev.cdrom.info = Can write DVD-R: 12:24:08 :: dev.cdrom.info = Can write DVD-RAM: 12:24:08 :: dev.cdrom.info = Can read MRW: 12:24:08 :: dev.cdrom.info = Can write MRW: 12:24:08 :: dev.cdrom.info = Can write RAM: 12:24:08 :: dev.cdrom.info = 12:24:08 :: dev.cdrom.info = 12:24:08 :: dev.cdrom.lock = 0 12:24:08 :: dev.raid.speed_limit_max = 200000 12:24:08 :: dev.raid.speed_limit_min = 1000 12:24:08 :: dev.scsi.logging_level = 68 12:24:08 :: dev.tty.ldisc_autoload = 1 12:24:08
产品设计
Introducing AWS Sandbox Environment: Learn AWS for Free Without a Credit Card
AWS Builder Center now offers free 8-hour sandbox environments for workshops. Here's how it works, who it's for, and how it compares to Free Tier, Skill Builder, and Educate.
产品设计
I Deleted 200 Lines of Code I Didn't Write and Learned More Than When I Wrote It...
Quick note before we dive in — I know I've been off track from the iOS/Swift series lately. I just...
AI 资讯
Applying SAST to Infrastructure as Code (Without TFSec)
Static analysis isn't just for application source code. Terraform, Pulumi, OpenTofu, and CloudFormation files are code too — and they get misconfigured just as often as a backend service. A public S3 bucket, a security group open to 0.0.0.0/0 , or an unencrypted RDS instance are all bugs you can catch before apply ever runs. TFSec is the tool most people reach for first, but it's not the only option on the OWASP Source Code Analysis Tools list . In this article I'll use Checkov , a free, open-source policy-as-code scanner built by Bridgecrew (now part of Palo Alto Networks), to scan a Terraform project end to end — from a local scan to a GitHub Actions gate that blocks merges on critical misconfigurations. The same approach works with OpenTofu and Pulumi projects too, since Checkov understands HCL directly and also has native support for Pulumi's rendered plan output and CloudFormation/ARM/Kubernetes manifests. Why Checkov? 100% open source (Apache 2.0), actively maintained, thousands of built-in policies. Understands Terraform, OpenTofu, CloudFormation, Kubernetes, Helm, Dockerfile, ARM, Serverless Framework, and Pulumi (via cdktf /synthesized plans) — one tool across most of your IaC surface. No account or API key required to run locally or in CI. Supports custom policies written in Python or YAML if the built-in rule set doesn't cover something specific to your org. ## 1. The sample infrastructure A small AWS setup with a few intentionally introduced misconfigurations — the kind that get merged during a rushed sprint: # main.tf provider "aws" { region = "us-east-1" } resource "aws_s3_bucket" "data" { bucket = "company-app-data-bucket" } # Vulnerable: bucket has no encryption, no versioning, and is publicly readable resource "aws_s3_bucket_acl" "data_acl" { bucket = aws_s3_bucket . data . id acl = "public-read" } resource "aws_security_group" "web" { name = "web-sg" description = "Allow web traffic" # Vulnerable: SSH open to the entire internet ingress { from_port
AI 资讯
Applying SAST to Any Application (Without Sonar, Snyk, Semgrep, or Veracode)
Most "how to add SAST to your pipeline" articles gravitate toward the same four names: SonarQube, Snyk, Semgrep, Veracode. They're solid tools, but they're not the only options, and sometimes you can't use them — budget constraints, air-gapped environments, licensing restrictions, or simply wanting something lightweight that lives entirely in your repo. The OWASP Source Code Analysis Tools page lists dozens of alternatives across every language. In this article I'll walk through applying Bandit , a free, open-source SAST tool for Python, to a real sample application — from finding vulnerabilities locally to wiring it into a CI/CD pipeline with GitHub Actions. The same workflow (install → configure → scan → fail the build on high-severity findings → track results over time) applies almost identically if you swap Bandit for other OWASP-listed tools like Brakeman (Ruby), FindSecBugs (Java), Gosec (Go), or Horusec (multi-language). Why Bandit? 100% open source (Apache 2.0), maintained under the PyCQA org. No account, no server, no license key — it runs as a CLI or a library. Understands Python's AST, so it catches real logic patterns, not just regex matches. Easy to tune with a config file and inline # nosec suppressions. ## 1. The sample application Let's use a small Flask app with a few intentionally introduced vulnerabilities — the kind of thing that slips into real codebases under deadline pressure. # app.py import subprocess import sqlite3 import pickle import yaml from flask import Flask , request app = Flask ( __name__ ) DB_PATH = " users.db " @app.route ( " /ping " ) def ping (): host = request . args . get ( " host " ) # Vulnerable: command injection via shell=True result = subprocess . run ( f " ping -c 1 { host } " , shell = True , capture_output = True ) return result . stdout @app.route ( " /user " ) def get_user (): user_id = request . args . get ( " id " ) conn = sqlite3 . connect ( DB_PATH ) cursor = conn . cursor () # Vulnerable: SQL injection via strin
AI 资讯
7 Dockerfile Mistakes That Are Quietly Costing You
Most Dockerfiles work. That's the problem — "it builds and runs" hides a lot of quiet costs in security, speed, and size that don't announce themselves until an audit, an incident, or a cloud bill does it for them. Here are seven mistakes I see constantly, and what to do instead. 1. Running as root By default, the process in your container runs as root — and if someone breaks out, they're root on a surface they shouldn't be. Add a non-root user and switch to it: RUN useradd --system --uid 10001 appuser USER appuser Cheap, and it closes off a whole category of "well, at least it wasn't root" incidents. 2. FROM some-image:latest latest is not a version — it's "whatever was newest when this happened to build." Two builds a week apart can produce different images with no diff to explain it, and a surprise base upgrade is a fun way to spend a Friday. Pin a specific tag, ideally by digest: FROM node:20.11.1-slim 3. Baking secrets into layers COPY .env . or ARG API_KEY followed by using it — and now the secret lives in an image layer forever , recoverable by anyone who pulls the image, even if a later layer deletes the file. Layers are immutable and additive; you can't delete your way out of a leak. Use build secrets ( --mount=type=secret ) or inject at runtime, never at build. 4. No .dockerignore Without one, COPY . . sweeps your .git directory, local env files, node_modules , and test data into the build context — bloating the image and, worse, potentially baking credentials and history into a layer. A five-line .dockerignore is one of the highest-leverage files in the repo. 5. Layer order that destroys your cache COPY . . RUN npm ci # ← reinstalls on EVERY code change Docker invalidates every layer after the first change. Copy the lockfile and install dependencies before copying the rest of your source, so a one-line code change doesn't trigger a full reinstall. This is a build-speed bug hiding as a style choice. 6. Leaving package manager cruft in the image RUN apt-get