AI 资讯
UFW and WireGuard: the tunnel is up and nothing goes through
The tunnel comes up. wg show prints a recent handshake. The client has its address inside the tunnel. And not a single byte reaches the internet. Almost every guide answers this with "open UDP 51820 in the firewall". You already did that — it is why the handshake works at all. The problem is somewhere else, and UFW makes the distinction easy to miss: Entering a machine and traversing it are two different permissions. ufw allow 51820/udp lets packets arrive at the server. Your clients' traffic does not stop there — it goes through the box and out the public interface. That path lives in the FORWARD chain, which UFW denies by default and which no allow rule touches. The four things to check, in order 1. IP forwarding — and the file that overwrites the other file This is the one that costs hours, because the setting looks done. UFW loads its own sysctl file at startup, and it takes precedence over the system one. A value you carefully set in /etc/sysctl.conf can be silently overwritten on the next ufw enable . The right place is /etc/ufw/sysctl.conf : net / ipv4 / ip_forward = 1 net / ipv6 / conf / default / forwarding = 1 net / ipv6 / conf / all / forwarding = 1 Then check the effective value, not the file you just edited: sysctl net.ipv4.ip_forward 2. Forwarding, which is not the same as ingress Targeted, and the one to prefer: sudo ufw route allow in on wg0 out on eth0 Or globally, in /etc/default/ufw : DEFAULT_FORWARD_POLICY = "ACCEPT" The second opens forwarding for every interface. It is a good ten-second diagnostic and a poor permanent configuration. 3. NAT, which UFW never adds on its own Without it, packets leave carrying their tunnel address, which nothing on the internet knows how to answer. In /etc/ufw/before.rules , at the very top , before the *filter line: *nat :POSTROUTING ACCEPT [0:0] -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE COMMIT Two classic mistakes here: putting this block after *filter (it is then ignored), and copying eth0 without chec
AI 资讯
Stop Fighting Your Fitness Data: Build a Serverless Warehouse with DuckDB and dbt
If you’ve ever tried to reconcile a night of sleep from an Oura Ring , a morning run from a Garmin watch, and active minutes from an Apple Watch , you know the "Dirty Data" struggle is real. Each platform has its own schema, its own definition of "active calories," and its own idiosyncratic export format. In the world of Data Engineering , this is a classic multi-source integration problem. But you don't need a massive Snowflake cluster to solve it. Today, we’re building a high-performance, serverless data pipeline to clean and normalize wearable data using DuckDB , dbt , and GitHub Actions . By leveraging a modern Serverless Data Pipeline and DuckDB's lightning-fast processing, we can turn a mess of CSVs into a structured Parquet -based personal data warehouse. The Architecture: From Chaos to Clarity Before we dive into the code, let’s look at how the data flows from your wearables to a clean, queryable state. graph TD A[Oura JSON] -->|Python Ingestion| D[(DuckDB Raw)] B[Garmin CSV] -->|Python Ingestion| D C[Apple Health XML] -->|Python Ingestion| D D --> E{dbt Models} E -->|Cleaning| F[stg_models] E -->|Normalization| G[int_health_metrics] G -->|Final Output| H[Gold Layer: Parquet Files] H --> I[Visualization / BI] subgraph GitHub Actions D E F G H end Prerequisites To follow along, you'll need: DuckDB : The "SQLite for OLAP" that makes local analytical processing insanely fast. dbt-duckdb : The adapter that lets dbt talk to DuckDB. GitHub Actions : Our free "orchestrator." Tech Stack : DuckDB, dbt, Python, Parquet. Step 1: The Ingestion Layer (Python + DuckDB) The first hurdle is getting disparate files (JSON, CSV, XML) into a unified storage format. DuckDB is magical here because it can query these files directly. We'll use a simple Python script to load these into a local .duckdb file. import duckdb def ingest_raw_data (): # Initialize the database con = duckdb . connect ( ' health_data.duckdb ' ) # Ingest Garmin CSV con . execute ( """ CREATE TABLE raw_garmin
AI 资讯
A Dead PID Held My Lock for 2 Hours: One Missing Line, Zero Output, exit 0 Every Time
For 30 straight days as a college student earning ¥100k/month, I posted to Instagram by hand, and then I burned out and stopped. Today the same job runs on a Claude Code autonomous environment, I touch nothing, and it holds up ¥1.2M/month in revenue. Except for the two hours when it quietly stopped: three consecutive launchd runs, zero pieces of content generated, last exit=0 every single time, and not one alert. The cause was a process that had already been killed, holding a lock file nobody would take away from it. Why this setup works From "doing the work" to "building the environment" The problem with updating social media by hand is that it burns willpower. No matter how motivated you are, sleep, health, and mood all fluctuate. During the period when I was laid off and my income went to zero, I had no mental slack for posting at all. The autonomous environment I spent six months building with Claude Code runs regardless of my emotional state. launchd calls a script, the script generates content with claude -p (MAX plan quota; paid APIs are off-limits), the output is queued for auto-posting, and it goes out to Instagram every day at 19:30. As long as this machinery keeps working, ¥1.2M/month in sales holds up without me lifting a finger. The mental model I want to hand you A lot of people think "automation = writing scripts," and that's only half right. A script is correct at the moment you write it. Given time, external dependencies break, processes die for reasons you didn't anticipate, and lock files turn into debris that blocks every future run. An autonomous environment that actually works is one that assumes breakage and carries a layer that repairs it. The lock story here is a textbook case. ~/dev/brand-404/sns/gen_feature.py is a script launched on a schedule by launchd that auto-generates Instagram feature articles. A single run takes a long time (up to three claude -p calls, plus image generation, adding up to tens of minutes), so it has a lock mechani
AI 资讯
How I wrote a Go message broker with a throughput of a million messages per second
I built HermitMQ entirely in Go. The main feature is ditching heavy wrappers like JSON in favor of a custom 29 byte binary protocol. Additionally, data transmission over the network uses a direct file to socket copy mechanism. I will go into detail about the architecture, data storage approaches, benchmark numbers, and show how it is implemented in code. The full source code for the HermitMQ project is available on GitHub: https://github.com/ekhidirov/hermitmq The problem with standard brokers and the cost of serialization When the message counter exceeds hundreds of thousands per second, the main problem for a Go developer is the garbage collector. If every message is parsed via standard JSON, the application starts allocating a massive number of small objects in memory. The GC wakes up too frequently, eating up CPU time and causing network latency spikes. To avoid triggering the garbage collector at every turn, I completely abandoned standard serialization libraries. Every message is packed into a custom header of exactly 29 bytes. In code, the message structure looks extremely simple: type Message struct { Magic byte Timestamp uint64 Offset uint64 KeySize uint32 PayloadSize uint32 RecordCount uint32 Key [] byte Payload [] byte } The first byte is a magic number for version checking and instantly discarding bad packets. Next come 8 bytes for the timestamp in nanoseconds and 8 bytes for the offset, which the broker fills in itself to maintain message order. Then come the key and payload sizes, 4 bytes each. Finally, 4 bytes are reserved for the record count to support batching. The broker reads the stream using the binary package and reuses buffers via sync.Pool. As a result, under standard loads, we achieve practically zero memory allocation. Being honest about allocations and plans for zero serialization To be completely honest: although the broker is incredibly frugal under standard loads, a memory management compromise still remains. An absolute victory over al
开源项目
.NET 10 dotnet tool exec: Pin the Version and Feed in CI
A CI step that says dotnet tool exec Some.Tool looks isolated, but it is not fully reproducible. Without a version, the command can resolve the latest package from the configured feeds. Machine-level NuGet settings can also change which feeds participate. I use .NET 10 dotnet tool exec with an exact @version and an explicit feed policy when I want one-shot tooling without a global install or a committed tool manifest. The command is stable from the .NET 10.0.100 SDK onward. Microsoft describes it as a temporary invocation: the package is downloaded to the NuGet cache, executed, and left out of PATH . That is convenient for CI, but temporary installation does not automatically mean deterministic selection. Why .NET 10 dotnet tool exec can drift The official command reference documents three useful selection modes: Some.Tool can resolve the latest version when no local manifest supplies one. Some.Tool@2.* stays on a major version, but still floats within that range. Some.Tool@2.4.1 requests one exact package version. For CI, I prefer the third form. A new tool release should arrive through a reviewed change, not because the next clean runner happened to restore later. The feed is a separate input. --add-source adds another source, and NuGet can query feeds in parallel. If the same package and version exists on more than one feed, the fastest response can win. That may be acceptable for interactive experimentation. It is a poor default for a build gate. .NET 10 is currently an active LTS channel . I still pin the SDK used by CI as well, because a package pin controls the tool package, not the CLI that resolves and launches it. Pin the version and feed together For a repository policy, I give dotnet tool exec a checked-in NuGet.Config . This sample uses a generated local feed, so it needs no credentials or external package call: <?xml version="1.0" encoding="utf-8"?> <configuration> <config> <add key= "globalPackagesFolder" value= "./artifacts/global-packages" /> </conf
AI 资讯
Every Laptop Is a Credential Store: Complete Map of Hidden Secrets
👉 TL;DR: A developer's laptop quietly becomes one of the densest credential stores in the organization. Cloud keys sit in ~/.aws, tokens pile up in shell history and .npmrc, SSH keys live in ~/.ssh, session cookies persist in the browser, and AI coding agents cache secrets in their own config files. None of it in a Git repository, none of it visible to the scanners most teams rely on. The laptop is the origin point: where credentials first land, where they dwell unrotated for months, and where infostealer malware goes looking. This article maps every location, explains why traditional scanning misses them, and lays out how to bring that hidden credential plane under the same discipline you apply to code. The perimeter moved to the laptop Security has spent a decade hardening repositories, pipelines, and vaults. The machine where developers actually work — installing CLIs, authenticating to clouds, running AI assistants — is still treated as trusted ground. But it isn't. A single laptop accumulates dozens of long-lived credentials across a dozen or more locations over months of normal work. No standard secrets scanner inspects any of them. Modern infostealers are written specifically to harvest the credential files that accumulate through ordinary development workflows. The laptop is not a new attack surface. It's one the industry has under-measured for years. Why your repo and CI scanners never see this Pre-commit and CI secret scanning inspect what reaches the repository or the pipeline. That is exactly why they miss the laptop. A credential sitting in ~/.aws/credentials or shell history never gets committed, so a repo scanner never sees it. Most of those credentials are long-lived and rarely rotated, dwelling on the machine for months. AI tooling accelerates the problem: more agents, more integrations, and more local config files mean more credentials in more places than manual hygiene can track. Structurally, the laptop is where every credential originates before
AI 资讯
GitHub Brings Stacked Pull Requests to Public Preview
GitHub has announced that Stacked Pull Requests are now available in public preview, introducing native support for breaking large software changes into smaller, dependent pull requests that can be reviewed and merged independently. By Craig Risi
AI 资讯
Checklist: Onboarding End-to-End Automation Frameworks to Harness CI
Successfully onboarding an automated test suite to Harness CI requires configuring infrastructure placeholders, secrets, pipelines, and branch protection rules. Here is a 10-step checklist to help you onboard your end-to-end (E2E) automation pipelines seamlessly. Step 1: Replace Infrastructure Placeholders Ensure your pipeline YAML definitions (e.g., .harness/e2e-poc.yaml and .harness/e2e-regression-parallel.yaml) contain your specific environment values: ORG_ID: Harness Organization Identifier PROJECT_ID: Harness Project Identifier GIT_CONNECTOR: Harness Git Connector for GitHub Enterprise access APP_REPO_NAME: Target repository in owner/repo format K8S_CONNECTOR: Kubernetes connector for build infrastructure K8S_NAMESPACE: Kubernetes namespace where build pods run Step 2: Configure Environment Secrets In Harness, set up the following runtime secrets: CONNECT_URL CONNECT_USERNAME CONNECT_PASSWORD Step 3: Setup PR Validation Pipeline Import your short-run pipeline YAML into Harness. Save it as your PR Validation Pipeline. Run a manual validation test using runtime overrides: TargetEnv = qa cucumberTags = @smoke Step 4: Verify Artifact Generation Confirm that the initial execution correctly generates and uploads all required outputs: JUnit Report: reports/junit-report.xml Test Reports: reports/** Failure Artifacts: test-results/** (screenshots, traces) Step 5: Setup Nightly Parallel Pipeline Import your parallel pipeline YAML into Harness. Save it as your Nightly Regression Pipeline. Run a manual validation test with target concurrency parameters: TargetEnv = qa cucumberTags = @regression cucumberParallel = 4 Step 6: Configure Automated Triggers & Branch Protection PR Trigger: Configured on pull requests with cucumberTags= @smoke . Nightly Schedule Trigger: Configured on a nightly cron schedule with cucumberTags=@regression and cucumberParallel=4. GitHub Branch Protection: Enable branch protection on target branches requiring the Harness PR pipeline status check to p
AI 资讯
End-to-End Setup Guide: Integrating Playwright + Cucumber with Harness CI
Integrating end-to-end (E2E) automation suites into enterprise CI/CD pipelines requires robust reporting, dynamic execution controls, and seamless artifact management. Here is a guide on setting up a Node.js + Playwright + Cucumber.js test suite using Harness CI , configured with dual-repository dependencies, parallel execution capabilities, and dashboard-ready reporting. Key Architectural Setup Two-Repo Architecture: Repository A (Application Automation Repo): Contains application-specific feature files, page objects, and pipeline definitions. Repository B (Shared Framework Repo): Hosts core framework utilities, custom assertions, and base drivers consumed as a pinned dependency. Tech Stack: Node.js, Playwright, Cucumber.js, Allure/JUnit reporting. Step 1: Configure Harness Connectors & Secrets Set up these foundational resources within your Harness account: Connectors: GIT_CONNECTOR: Grants access to both application and framework GitHub repositories. K8S_CONNECTOR: Manages the Kubernetes build infrastructure. Secrets: CONNECT_URL, CONNECT_USERNAME, and CONNECT_PASSWORD (and proxy settings if required). Step 2: Configure Pipelines Import your execution configurations using YAML files inside .harness/: Standard Run (.harness/e2e-poc.yaml): Used for fast PR checks. Parallel Regression (.harness/e2e-regression-parallel.yaml): Used for scheduled, high-volume regression runs. Replace placeholders such as , , and to map to your cluster environment. Step 3: Define Pipeline Triggers Set up two primary execution workflows: Pull Request (PR) Trigger: Event: Pull Request to main/POC branch. Runtime Variables: cucumberTags= @smoke Scheduled Nightly Trigger: Event: Scheduled Cron. Runtime Variables: cucumberTags=@regression, cucumberParallel=4 Step 4: Test Report & Artifact Collection To ensure test metrics display properly on the Harness dashboard, configure both JUnit parsing and raw artifact archiving. Generated Outputs: reports/junit-report.xml (parsed by Harness for test
AI 资讯
How to Configure Parallel Execution in TestNG vs. Custom Excel Allocator
Optimizing test execution speed is essential for keeping build pipelines lean. Depending on how your framework is structured, you can achieve full parallel execution either natively using TestNG ** or dynamically using a **Custom Excel Allocator . Here is a step-by-step guide on configuring both approaches, along with a comparison to help you choose the right strategy. Strategy 1: Native TestNG Parallelization (Recommended for Code-Native Suites) TestNG natively supports parallel execution at the methods, classes, tests, or instances level using its XML configuration or Maven parameters. 1. Update testng_regression.xml Modify the tag to set the execution mode and thread pool size: <suite name= "Regression" parallel= "methods" thread-count= "10" > 2. Configure pom.xml for Dynamic Overrides Allow developers and CI pipelines to override execution settings without altering XML files by adding these lines inside the block of the maven-surefire-plugin: <parallel> ${parallel} </parallel> <threadCount> ${threadCount} </threadCount> 3. Execution Commands Default Run: mvn clean test -P runTestNGTests Override Thread Count Dynamically: mvn clean test -P runTestNGTests -DthreadCount = 15 Full Parallel Execution (Match CPU Core Count): mvn clean test -P runTestNGTests -Dparallel = methods -DthreadCount = 24 Strategy 2: Custom Allocator & Run Manager (For Excel-Driven Suites) If your framework relies on an Excel-driven Run Manager to parse keyword flows and data sheets dynamically, parallelism is managed via a custom ExecutorService fixed thread pool. Execution Command mvn clean test -P runAllocator How it works: The allocator reads active test rows (Execute=Yes), dynamically assigns thread pools based on target thread properties, and dispatches concurrent runs. Comparison: Allocator (Run Manager) vs. Native TestNG Feature Allocator (Run Manager) TestNG Native Entry Point allocator.Allocator.main() via Maven Exec Plugin maven-surefire-plugin executing testng.xml Test Selection Re
AI 资讯
AI Observability Explained: What It Is and How It Works
Traditional monitoring rests on one quiet assumption that nobody ever writes down: the same input gives you the same output. Something breaks, you replay the request, you watch it break again, you fix it. Now send the same request to a model twice. You get two different answers, and neither one of them threw an error. AI observability is the practice of recording what happened inside an AI system on every request: the prompt, the model version, tokens, cost, latency, tool calls, and a judgement of whether the output was any good. Monitoring tells you the service is up. Observability tells you why it answered that way. That gap is the whole story here. Why your current monitoring stack misses all of this Your existing setup is watching for crashes. Status codes, error rates, p99 latency, memory. All of it is designed around the idea that a broken thing looks broken. An AI feature failing looks nothing like that. It returns HTTP 200 in 900ms, with grammatically perfect prose that happens to be wrong, or that quietly ignored the document you retrieved for it, or that called the refund tool when the user only asked a question. Your dashboard sees a healthy service, because by every measure it has, the service is healthy. And there are whole categories of failure your stack has no field for. It has nowhere to put "this response cost 14 cents", or "the model version changed under us last Tuesday", or "the retrieved context was garbage". Those are not infrastructure facts, and standard telemetry was never built to carry them. Something has to hold those fields instead, which is the entire reason this tooling exists. My team uses Bifrost , so I will use it as the example throughout this post. It's an open-source AI gateway from Maxim, so anything I claim about what it records per request is something you can go check line by line. Most tools here put their telemetry story on a marketing page and stop there. What one AI request actually looks like when you trace it This is t
AI 资讯
[Technical Discussion] IPC Message Queue Tuning for WLOADCTL on Linux
WLOADCTL is built as a distributed scheduling platform composed of multiple cooperating processes. Communication between different nodes, such as: Server ↔ Agent Server ↔ Client is handled through TCP/IP socket communication. However, communication between components on the same node relies heavily on Linux Inter-Process Communication (IPC) mechanisms, including: Message Queues Shared Memory Semaphores In some environments, the default Linux IPC configuration may not be sufficient for high-volume scheduling workloads. When this happens, WLOADCTL may encounter message queue-related errors or communication bottlenecks. This article explains how to: Check current IPC limits Increase message queue capacity Inspect IPC resource usage Remove unused IPC resources Understanding Current IPC Limits Before making any changes, it is important to inspect the current IPC configuration. Use: ipcs -l This command displays the system-wide limits for IPC resources, including: Maximum number of semaphore sets Maximum number of semaphores Maximum message queue size Maximum shared memory limits Pay special attention to the Message Limits section. Example: ------ Messages Limits -------- max queues system wide max size of message (bytes) default max size of queue (bytes) If the value of: default max size of queue (bytes) is around: 16384 the queue capacity may be too small for larger scheduling environments. Increasing Message Queue Capacity If the current limits are low, we recommend adjusting the Linux kernel IPC parameters. As the root user, edit: /etc/sysctl.conf and add the following settings: kernel.msgmni=1600 kernel.msgmax=8192 kernel.msgmnb=1638400 Parameter descriptions: Parameter Description Typical Default Recommended msgmni Maximum number of message queues 16 1600 msgmax Maximum size of a single message (bytes) 8192 8192 msgmnb Maximum capacity of a message queue (bytes) 16384 1638400 In WLOADCTL, a typical internal message is approximately: 512 bytes After modifying the con
AI 资讯
Docker Compose Isn't What I Thought It Was
post 7: A practical guide to understanding Docker Compose—what it is, how it works, and the misconceptions that catch most beginners. You've mastered single containers. Now it's time to build a real application. A frontend. A backend. A database. A Redis cache. Suddenly you're juggling multiple docker run commands. Ports. Networks. Volumes. Environment variables. Chaos. Then someone says: "Just use Docker Compose." It works beautifully. But here's the twist most people never realize… Why Docker Compose Exists Imagine starting an application like this: Frontend Backend PostgreSQL Redis Running each container manually quickly becomes repetitive and error-prone. Docker Compose lets you describe your entire application in a single YAML file and start everything with one command. Instead of remembering dozens of commands, you define your infrastructure once. What Docker Compose Actually Is Docker Compose is not a container orchestrator . Docker Compose is a tool that reads your Compose YAML file and uses the Docker Engine to create and manage the resources defined in it.” Modern Docker uses Compose V2 , which runs as: docker compose instead of the older: docker-compose Compose runs only when you execute a command. It creates the required Docker resources, starts the containers, and then exits. This makes it ideal for development, testing, and single-host deployments , but it doesn't provide orchestration features like automatic scheduling, self-healing, or multi-node management. A Simple docker-compose.yml services : web : build : . ports : - " 8080:80" environment : - DB_HOST=db depends_on : - db db : image : postgres:15 volumes : - postgres_data:/var/lib/postgresql/data redis : image : redis:alpine volumes : postgres_data : YAML Quick Reference Key Purpose services Defines containers (web, db, redis) build Builds an image from a Dockerfile image Uses an existing image from a registry ports Maps host ports to container ports environment Sets environment variables depend
AI 资讯
A Security Fix Should Show Where the Attack Stopped
The concrete problem A security pull request can be green for the wrong reason. Unit tests may pass, the vulnerable endpoint may return a different status code, and a scanner may stop reporting the original finding. None of those results necessarily shows that the attacker lost the capability that mattered. The same identity might reach the sensitive action through another route, inherit a broader token, or trigger an equivalent workflow with slightly different input. This becomes especially uncomfortable when an automated tool proposes or reviews the fix. A plausible patch explanation is not behavioral evidence. The reviewer still needs to know which identity was used, which preconditions were established, which requests ran, where privilege was gained before the fix, and at which exact step the patched build denied it. Without that trace, “fixed” is partly an assertion about code rather than an observation of the attack path. The current signal On August 17, Wiz described a GitHub Actions script-injection flaw in a Snowflake repository. The vulnerable workflow change reached production on June 18 and Wiz reported exploiting it on June 23. The final squash commit credited Copilot Autofix as a co-author, while AI-assisted review did not flag the injection. Wiz later clarified that it could not determine whether the code change itself was AI-generated. That distinction matters: the lesson is about assurance around AI-assisted workflows, not proof that a model wrote the bug. The Hacker News discussion was active when RayTally captured it at 2026-08-18 00:33 UTC: 306 points, 123 comments, and rank 5. Those are historical attention numbers, not market validation. The useful engineering signal is narrower. Teams now have a concrete incident in which an apparently protective condition and an escaping routine still produced a reachable credential-exfiltration path. Bright STAR and StackHawk show that dynamic testing in CI is already real. Bright documents building and star
AI 资讯
Your backup is not a backup until you have restored it
This is an English write-up of a post from my Japanese dev diary. Original: https://saas-diary.com/tech-log/backup-restore-drill-automation/ For over a year, my backup job has reported success every single night. Green check, every day, no exceptions. Then I asked myself one question and went cold: "How many times have I actually restored from it?" Zero. Not once. "It was backed up" and "it can be restored" are different states My setup has two paths. One mirrors all source to a private repo. The other packs the things I can never recreate — notes, config, and Android signing keys — into an encrypted bundle and ships it to a private channel every night. Both were green every day. But green only proved the upload finished . It never proved the contents were right, or that the archive could even be opened. Within one month, I had two failures that stayed green the whole time. Failure 1. The collector for signing keys used three hardcoded paths. I kept shipping new apps, so the number of keys kept growing — but the collector didn't. By the time I noticed, 7 of 10 keys were missing from the backup . Five of those apps were live on the store. If my machine had died, I could never have shipped an update for them again. The backup reported success every night through all of it. Failure 2. The mirror push failed 7 days in a row (a large binary hit the host's file-size limit). But the script printed "✅ done" and returned exit code 0 even when one half failed. A failure that isn't visible isn't a failure — it's a time bomb. So I automated a restore drill Once a month, a job now does this: Rebuild the encrypted bundle (without shipping it) Actually decrypt it with the stored passphrase Extract it and count what's inside Check the mirror is not stalled (latest commit timestamp via API) Delete the scratch folder and the generated bundle The encryption is openssl-compatible AES-256-CBC with PBKDF2 (SHA-256, 100k iterations). I deliberately avoided depending on the openssl binary,
开发者
Understanding chmod Without Memorizing Numbers
How Linux file permissions actually work under the hood, why symbolic mode is your best friend, and how to stop blindly typing chmod 777. Every Linux engineer has been there. You write a brand-new bash script, try to run it from your terminal, and hit an immediate roadblock: $ ./backup.sh bash: ./backup.sh: Permission denied You open your search engine or ask a chat assistant for help. Within seconds, you find an answer that tells you to run: chmod 777 backup.sh You run the command, hit enter, and the script runs. Problem solved, right? Not quite. In fact, you just opened the digital front door of that file to every single user and background service on the entire operating system. When I started managing Linux servers years ago, permissions felt like a strange puzzle of three-digit math problems. People kept throwing numbers around: 755 for scripts, 644 for web pages, 600 for SSH keys, and 777 whenever something broke and nobody knew why. I memorized those numbers like cheat codes in a video game. But whenever I had to handle a real permission problem, like giving a development team write access to a shared log folder without letting them delete each other's files, memorized numbers fell apart. Here is the secret: you do not need to do binary math or memorize three-digit codes to master Linux permissions. Linux has a built-in, human-readable permission syntax called symbolic mode . Once you understand how Linux looks at files, who owns them, and what actions each permission controls, chmod becomes one of the most intuitive tools in your terminal. Let's break down how it all works step by step. 1. What chmod Actually Does The name chmod stands for change mode . In Unix and Linux systems, every single file and directory has a "mode". That mode determines who is allowed to read it, write to it, or run it. When you run chmod , you are simply updating those access bits inside the Linux filesystem inode. To see the current mode of your files, open any terminal and run ls
AI 资讯
Network Devices Explained — The Foundation Every Cloud & DevOps Engineer Needs
🌐 Network Devices Explained The Foundation Every Cloud & DevOps Engineer Needs Series: Networking Fundamentals for Cloud & DevOps — Part 1 of 6 Before VPCs, subnets, route tables, and security groups make sense, you need to understand what's happening beneath them. This series builds that foundation — starting with the devices that make networks work. Why Networking Before Cloud? I hit a wall during my AWS VPC sessions. Route tables, subnets, gateways, NACLs — the concepts existed in isolation. I could follow steps in the console, but I couldn't reason about why traffic was or wasn't flowing. The fix wasn't more AWS documentation. It was going back to networking fundamentals. Once I understood what a router actually does — how it makes forwarding decisions, what a routing table really is — the AWS route table stopped being a mysterious config screen and became something I could think through. That's what this series is. Six posts covering the networking concepts that directly underpin Cloud and DevOps work. No exam prep framing, no CCNA depth. Just what you actually need. 1. What is a Host? A host is any device that participates in network communication by sending or receiving traffic. That's broader than most people assume. Examples: your laptop, your phone, an EC2 instance, a web server, a virtual machine. The word "host" doesn't imply a server — your laptop is a host just as much as a data center machine is. 2. Client vs Server — Roles, Not Hardware A client is a host that initiates a request. A server is a host that responds. The critical point: a server is not a special type of computer . It's just a computer running software that listens and responds. Your Browser (Client) │ │ HTTP Request ▼ Web Server (Server) │ │ HTTP Response ▼ Your Browser (Client) The same machine can be a client in one communication and a server in another. Your EC2 running a web app is a server to users hitting it — and a client when it queries RDS. 3. IP Address — The Network Identity
AI 资讯
Why I left Warehouse out of our Fabric deployment scope
title: Why I left Warehouse out of our Fabric deployment scope published: true tags: microsoftfabric, datawarehouse, cicd, devops Our Fabric deployment pipeline handles sixteen item types. Warehouse is not one of them, and that was deliberate. DEFAULT_ITEM_TYPES = [ " DataPipeline " , " Lakehouse " , " Notebook " , " SemanticModel " , # "Warehouse" is intentionally excluded. Warehouse schema deployment must # be handled separately to avoid schema reset risk during publish. " Environment " , " Eventhouse " , ... ] The reason Publishing a warehouse through this path can reset its schema. Not "might behave unexpectedly". The failure mode is that a deployment intended to be additive removes structure, and the thing that removes it is the same routine that successfully deploys the other sixteen types. The choice that follows Two options once you know that. Include it and hope nobody deploys a warehouse without reading the docs. The pipeline supports everything, and one day someone promotes a change on a Friday and finds out. Or exclude it, document why, and handle warehouse deployment as its own problem with its own tooling. I took the second. An automation that covers most cases and silently corrupts the rest is worse than one that covers most cases and refuses the rest. The refusal is visible. The corruption is not. Making the exclusion loud An exclusion is only useful if someone notices it. Three things help: The comment sits inside the list , not in a doc nobody opens. Anyone reading the item types sees the gap and the reason in the same glance. It is in the README under known limitations, next to the other things the framework does not do. There is a test. It asserts Warehouse is absent from the default scope: def test_warehouse_stays_excluded ( self ): """ Warehouse publish can reset schema, so it is handled separately. """ self . assertNotIn ( " Warehouse " , deploy . DEFAULT_ITEM_TYPES ) That test looks silly. It is asserting that a string is missing from a list.
AI 资讯
Unified Secrets Security with GitGuardian and AWS Secrets Manager
By: Pierre Le Clezio, Lead Product Manager – GitGuardian; Nic Gumina, Senior Security Consultant – AWS; Manu Chandrasekhar, Senior DevOps Consultant – AWS; Dan Parlin, Security Consultant – AWS This article was originally published at AWS blogs . The rise of AI coding assistants and Model Context Protocol (MCP) servers has accelerated the secret management challenge as developers increasingly share configuration files and context with AI tools that inadvertently expose sensitive credentials. API keys, access tokens, and credentials end up in Git repositories and CI/CD logs. Organizations lack answers to critical questions. They don't know which vaulted secrets have been exposed in code, whether developers have shared credentials through AI tool configurations, how many duplicate credentials exist across accounts, or how many orphaned secrets remain that no application uses. The visibility gap leads to: Credential exposure : Hardcoded secrets in version control systems create attack vectors that persist even after rotation Secret sprawl : Duplicate credentials across accounts expand your attack surface Compliance gaps : Inability to track secret lifecycles undermines audit requirements Remediation delays : Without correlation between secret inventory and code exposure, security teams lack the context to prioritize and act quickly With multi-account AWS architectures, the need for unified visibility becomes critical. Organizations need more than just a vault. They need visibility across the entire secret lifecycle, from developer workstations to production environments. GitGuardian and AWS Secrets Manager GitGuardian is an AWS Partner specializing in non-human identity (NHI) security, which focuses on protecting machine credentials such as API keys, service accounts, tokens, and secrets management. GitGuardian can be integrated with code repositories, container registries, package registries, documentation platforms, and messaging channels. GitGuardian's integration w
AI 资讯
NuGet Restore Failing with 'Unable to find version' Package? Check Your NuGetToolInstaller Version!
The Problem In one of our Azure DevOps pipelines, nuget restore suddenly started failing with an error stating, in essence, that the requested package could not be found in the referenced version. The task referencing the package hadn't changed — yet the restore stage kept failing. At first glance, this looks like an issue with the package source, some caching effect, or a broken .nuspec/lockfile. It wasn't. The Root Cause The actual culprit was the version of the NuGetToolInstaller@1 task itself. The pipeline had NuGet pinned to version 6.12.2. The Fix Bump the versionSpec in the NuGetToolInstaller@1 task from 6.12.2 to 7.9.0: - task : NuGetToolInstaller@1 displayName : ' Use NuGet 7.9.0' inputs : versionSpec : 7.9.0 checkLatest : false That's it. After the update, nuget restore ran through cleanly again.