AI 资讯
File Compression in Linux Explained Simply (tar, gzip, zip & unzip)
Working with files in Linux isn't just about creating and editing them. Sometimes you need to: Archive multiple files into one Compress files to save disk space Share files with others Create backups Linux provides several tools for this, each with a different purpose. Let's simplify them. What is File Compression? File compression reduces the size of a file. Benefits: Saves disk space Faster file transfers Easier backups Reduces bandwidth usage Example: A 100 MB log file might become a much smaller compressed file, depending on its contents. Archive vs Compression Many beginners think they're the same. They are not. Archive Combines multiple files into a single file. Example: photos/ docs/ notes.txt ↓ backup.tar Compression Reduces the size of a file. Example: backup.tar ↓ backup.tar.gz 👉 tar archives files. gzip compresses them. 1. Create an Archive with tar tar -cvf backup.tar Documents/ #Create an archive tar -tvf backup.tar #View archive contents tar -xvf backup.tar #Extract an archive Options: c → Create v → Verbose (show progress) f → File name x → Extract Best for: Backups Bundling multiple files Moving folders 2. Compress with gzip Compress a file: gzip file.txt # Creates file.txt.gz # Result file.txt.gz gunzip file.txt.gz # decompress gzip -k file.txt # Keep original file Best for: Log files Large text files Saving disk space 3. Archive and Compress Together Most common command: # Create compressed archive tar -czvf backup.tar.gz Documents/ # Extract tar -xzvf backup.tar.gz Options: z → Use gzip compression 👉 This is one of the most common backup commands in Linux. 4. Working with ZIP Files # Create ZIP zip -r project.zip project/ # Extract unzip project.zip # List contents unzip -l project.zip Best for: Sharing files with Windows users Cross-platform compatibility 5. Compare the Tools Tool Purpose Best For tar Archive files Backups gzip Compress files Saving space tar + gzip Archive and compress Linux backups zip Archive and compress Sharing files across
AI 资讯
Working with Let's Encrypt's Short-Lived tlsserver and shortlived Profile Certificates
Let's Encrypt issues TLS certificates with a 90-day validity period by default. However, as the industry is gradually shortening TLS certificate lifetimes—with the maximum eventually expected to fall to 47 days—Let's Encrypt already offers certificates using the tlsserver profile with a validity period of 45 days. Compared with the current default classic profile, the tlsserver profile removes deprecated attributes such as the Common Name. Because it follows the latest recommended configuration, it also produces slightly smaller certificates. The differences between the profiles are documented on the following page. If you have already automated certificate issuance and renewal, it is worth considering an early move to the tlsserver profile. Certificate Profiles - Let's Encrypt Certificates issued with the classic profile are currently valid for 90 days. However, the validity period is scheduled to be shortened to 64 days in February 2027 and then to 45 days in February 2028. Certificate renewal automation is easy to leave untouched once it is working, and many monitoring systems also use fixed day-based thresholds. Both renewal automation and monitoring therefore require careful review. Decreasing Certificate Lifetimes to 45 Days - Let's Encrypt With only about six months remaining before the validity period is reduced to 64 days, now is a good time to begin validating your systems. Let's Encrypt also provides the shortlived profile for certificates that support IP addresses. These certificates are valid for only six days. With such a short lifetime, using them without automation is no longer practical. 6-Day and IP Address Certificates - Let's Encrypt To issue certificates using any of these profiles, you need an ACME client that supports ACME profile selection. Widely used clients such as Certbot should be able to issue them without difficulty. Issuing a certificate with the new tlsserver or shortlived profile is straightforward. The harder part is keeping it ren
AI 资讯
What Actually Happens After You Send a Webhook
The first version of a webhook is always the same four lines: await fetch(customer.webhookUrl, { ...
AI 资讯
Building an On-Premise Kubernetes Cluster — Part 6: Deploying, Updating, and Scaling Your Own Application
🇧🇷 Leia a versão em português aqui In Part 5 of this series, we validated the cluster end to end by deploying Nginx. Now let's go one step further: build a custom application's Docker image, publish it, get it running in the cluster, and explore day-to-day operations — version updates, rollback, and scalability (both manual and automatic). As an example, we used a simple REST API ( myapp.war ), built with Spring Boot, purely for illustration — the process applies to any application packaged as a container image. Building the application's Docker image The first step is writing the application's Dockerfile . In this example, a lightweight base image ( alpine ) was used, with Java 11 installed to run the application: FROM alpine WORKDIR /opt/app RUN apk update && apk add vim openjdk11-jre COPY runapp.sh . CMD ash runapp.sh Building the image docker image build -t oregontecnologia/myapp-api:1.0.0 . Publishing the image Before using the image in the cluster, it needs to be available in some registry — either Docker Hub or a private registry . If you'd rather host your own on-premise registry (recommended for corporate environments or those without internet access), check out the companion article on creating a local registry server . To publish to Docker Hub: docker login username: password: docker push oregontecnologia/myapp-api:1.0.0 Deploying the application With the image published, you can check the cluster's current state before proceeding: kubectl get pods -o wide kubectl get deploy -o wide Create the Deployment directly from the command line, pointing to the published image: kubectl create deploy myapp-deploy --image = oregontecnologia/myapp-api:1.0.0 Unlike previous examples in this series (where we used YAML files with kubectl apply -f ), here the Deployment is created directly via the command line with kubectl create deploy . Both approaches are valid — YAML files are more suitable when you need to version and consistently reapply configurations. Exposing the
AI 资讯
Building an On-Premise Kubernetes Cluster — Part 5: Deploying Your First Container
🇧🇷 Leia a versão em português aqui In previous parts of this series, we built the cluster from scratch: prepared the environment (Part 1), installed containerd and Kubernetes (Part 2), initialized the control-plane (Part 3), and joined the workers (Part 4). With the cluster up and all nodes in Ready state, it's time to actually put it to work: let's deploy our first application. In this article, we'll use Nginx as an example — a classic use case for validating that the cluster is working end to end, from pod creation to service exposure. Organizing the files First, create a directory to organize this deployment's manifests: mkdir nginx cd nginx Keeping Kubernetes manifests organized in per-application directories is a good practice that makes maintenance and versioning (e.g., with Git) easier as the cluster grows. Creating the Deployment A Deployment is the Kubernetes object responsible for managing pod replicas, ensuring the desired number of instances is always running — and handling things like rolling updates and automatic recovery in case of failure. Create the file nginx-deployment.yaml with the following content: apiVersion : apps/v1 kind : Deployment metadata : name : nginx-deployment labels : app : nginx spec : replicas : 2 selector : matchLabels : app : nginx template : metadata : labels : app : nginx spec : containers : - name : nginx image : nginx:1.14.0 ports : - containerPort : 80 This manifest defines: 2 replicas of the Nginx pod ( replicas: 2 ), distributed across the available workers; A selector that ties the Deployment to the pods via the app: nginx label; The nginx:1.14.0 image, exposing container port 80 . Applying the Deployment With the file saved, apply it to the cluster: kubectl apply -f nginx-deployment.yaml kubectl will create the Deployment, and from there Kubernetes takes care of scheduling the 2 pods across the available workers. Checking the Deployment To confirm the Deployment was created and has the desired number of replicas running
AI 资讯
Building an On-Premise Kubernetes Cluster — Part 2: Installing Containerd and Kubernetes
🇧🇷 Leia a versão em português aqui In Part 1 of this series, we prepared the environment: defined the hardware, configured /etc/hosts , adjusted the firewall, and disabled SWAP on all nodes. Now that the foundation is ready, it's time to install the container runtime ( containerd ) and the Kubernetes packages themselves ( kubelet and kubeadm ). All the steps below should be run on all servers in the cluster — master and workers — unless stated otherwise. Loading kernel modules Kubernetes, through containerd, depends on two Linux kernel modules: overlay (for the layered filesystem used by containers) and br_netfilter (so that bridge network traffic passes through iptables rules). For these modules to load automatically on every boot, create the file /etc/modules-load.d/containerd.conf : overlay br_netfilter And, to load them immediately (without needing a reboot), run: $ sudo modprobe overlay $ sudo modprobe br_netfilter Adjusting kernel network parameters Create the file /etc/sysctl.d/99-kubernetes-k8s.conf with the following parameters: net.bridge.bridge-nf-call-iptables = 1 net.ipv4.ip_forward = 1 net.bridge.bridge-nf-call-ip6tables = 1 These parameters ensure that network traffic between pods and services is correctly routed and filtered by Kubernetes. To apply the settings without restarting the server: $ sudo sysctl --system Installing containerd Containerd is the container runtime used by the cluster. In this case, we'll install it through Docker's official repository, using only the containerd.io package (without installing full Docker). 1. Download the repository's GPG key: curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/docker.gpg 2. Create the repository file at /etc/apt/sources.list.d/docker.list : deb [ arch = amd64] https://download.docker.com/linux/debian bullseye stable 3. Update the package list and install containerd: sudo apt-get update sudo apt-get install containerd.io 4. Generate the default
开发者
Building an On-Premise Kubernetes Cluster — Part 1: Preparing the Environment
🇧🇷 Leia a versão em português aqui This is the first part of a series where I'll share, step by step, how I built my own on-premise Kubernetes cluster, without relying on any cloud provider. The goal is to document the whole process — from environment preparation to a working cluster — as a reference for anyone studying the topic or looking to replicate the same setup at home or at work. I used VPS (Virtual Private Server) and VM (Virtual Machine) for this cluster. However, it can also be set up on physical machines (Bare Metal). Bye the end of this series, it will be easier to understand cloud clusters on AWS (EKS), Google (GKE) and Azure (AKS). In this first part, we'll cover everything needed before installing any Kubernetes component: hardware requirements, basic network configuration, firewall rules, and a few mandatory operating system adjustments. Requirements The following topology was used for this cluster: 3 servers in total 1 master server (control-plane): 2 CPUs (cores) and 2 GB of RAM 2 worker servers (slaves): 1 CPU and 1 GB of RAM each Root access on all machines This is a minimal setup, ideal for study, lab, or testing environments. For production, resources should be scaled according to expected load. Configuring the hosts file Before installing anything, it's important for the machines to resolve each other by name, not just by IP. Edit the /etc/hosts file on all servers and add the corresponding entries: 10 . 0 . 10 . 100 master . company . local master 10 . 0 . 10 . 101 slave01 . company . local slave01 10 . 0 . 10 . 102 slave02 . company . local slave02 This ensures that, later on, the Kubernetes components can correctly resolve node names. Configuring the Firewall Kubernetes depends on specific ports being open between nodes so the control-plane can communicate with the workers (and vice versa). The ports vary depending on the server's role in the cluster. On the master server: Port Protocol 6443 TCP 2379-2380 TCP 10250 TCP 10251 TCP 10252 TCP
AI 资讯
I generated 207 MCP tools from an OpenAPI spec. Generating them was the easy part.
Every MCP server I've read that wraps a third-party REST API has the same shape: someone picked fifteen or twenty endpoints that seemed useful, hand-wrote a Zod schema for each, and shipped it. That works for about three months. Then the API adds a field, deprecates an enum value, renames a query parameter. The wrapper doesn't notice, because nothing in it is connected to the API's own description of itself. The schemas drift. The model starts getting rejected by the upstream API for reasons it can't see, and you get to debug an LLM guessing at a shape that stopped being true in February. The other failure is quieter. You need endpoint twenty-one — the one about persistent disks, or scaling, or environment groups — and the author skipped it. Now you're back to curl , except the agent is holding half the context and you're holding the other half. I wanted neither, so I built render-useful-mcp : an MCP server for Render where every API tool is generated from Render's own OpenAPI document. All 207 endpoints, no curation. The generating part took a weekend. Everything after that was the actual work. Make the generator refuse to guess The tempting way to write a spec-to-tools generator is to make it forgiving. Skip what you can't parse, fall back to { type: "object" } when a $ref gets hairy, log a warning and move on. You get 207 tools on the first run and feel great. You also get tools that lie. A parameter typed as a free-form object when the API actually wants one of four enum values is worse than no tool at all — the model will confidently produce garbage, and the failure surfaces three layers away from the cause. So the generator is fail-closed. It aborts the build, loudly, on: An operation whose tag doesn't map to a known toolset. Render added a resource category and I haven't classified it yet. That's my problem to solve, not something to paper over. A tool name collision. Two operations deriving the same name means my naming scheme is wrong. A cyclic $ref it can'
AI 资讯
Internet & Networking Explained, The Foundation Every DevOps Engineer Should Know.
When you open a website, send a message, or watch a YouTube video, many technologies work together in the background. As a beginner in DevOps, understanding these basic networking concepts will help you understand how applications communicate over the internet. **What Is a Protocol? A protocol is a set of rules that devices follow when communicating with each other. Think about two people having a conversation. For communication to be successful, both people must speak the same language and follow simple rules, like taking turns to talk and listening before responding. Computers work the same way. They use protocols to know how to send, receive, and understand information. Without protocols, computers would not be able to communicate with one another. **2. What Is Packet Switching? **Imagine you want to send a large book to a friend. Instead of sending the entire book in one huge package, you divide it into many smaller packages. Each package travels separately and, when they all arrive, your friend puts them back together in the correct order. This is exactly how the internet works. When you visit a website, your data is broken into small pieces called packets. Each packet travels across the internet and is reassembled when it reaches its destination. This process is called packet switching, and it makes internet communication faster and more reliable. **3. What Is an IP Address? **Every house has a unique address that helps delivery drivers know where to deliver packages. Similarly, every device connected to the internet has a unique Internet Protocol (IP) address. An IP address helps the internet know exactly where information should be sent. Without an IP address, websites, computers, and phones would not know where to send or receive data. **4. What Is TCP/IP? **Breaking data into packets is not enough. The packets must also arrive correctly. This is where TCP/IP (Transmission Control Protocol/Internet Protocol) comes in. IP finds the correct destination for ea
AI 资讯
A Dead Man's Switch for Your Monitoring Stack
Your monitoring catches problems on everything except itself. Here is how an always-firing Watchdog alert plus an external heartbeat check turns silence into a signal, so you find out when your own alerting dies. TL;DR A monitoring system can't reliably monitor its own failure, so use a dead man's switch. Create an always-firing Prometheus Watchdog alert and route it to an independent external heartbeat service. As long as the monitoring pipeline is working, the Watchdog continuously refreshes the heartbeat. If Prometheus, Alertmanager, or the delivery path fails, the heartbeat stops and the external service alerts you through a separate channel. The key is independence: the system responsible for detecting that your monitoring is down must not depend on the monitoring stack itself. One of the traps of creating alerts on a monitoring stack is the hidden assumption that the mechanism evaluating the alert is running properly and has the ability to evaluate it. Prometheus watches your hosts and Alertmanager delivers the warnings. But what watches Prometheus? If something goes wrong and the monitoring stack fails in the middle of the night, no alerts are going out but there is definitely a problem. That is the failure mode that you should be most concerned about, because it is the one your monitoring cannot report on. The fix is an old idea with a grim name: a dead man's switch. A train's dead man's switch stops the train when the operator stops holding it down. The safe state requires continuous positive action, while the absence of that action is what triggers the response. Applied to monitoring, it means building one alert whose silence is itself the alarm. Step one: an alert that always fires This feels backwards the first time you see it, and it took me a little time to get it right. Basically, you create an alert with a condition that is always true, so it fires constantly, forever, on purpose. In the Prometheus world this is conventionally called Watchdog. - aler
AI 资讯
Blast Radius: What a Leaked Secret Breaks
Why identity-local signals and topology signals are two layers of the same blast radius The credential with the widest blast radius sometimes has no secret to flag. See how GitGuardian and Anyshift rank risk by what actually breaks. By Louis Fradin • 23 Jul 2026 • 7 min read 👉 TL;DR: Identity-local signals show whether a credential or machine identity is risky. Topology signals show what breaks if that identity is abused. GitGuardian identifies and ranks exposed credentials and risky machine identities; Anyshift's graph adds downstream context by showing which services depend on the resources those identities reach. Together, they help teams prioritize by both credential severity and operational blast radius. A leaked credential is also a topology problem A leaked credential creates risk beyond the identity itself. Its real impact depends on the services and resources connected to what that credential can access. Identity-local signals answer the first question: how risky is this credential or machine identity on its own? Is it plaintext? Guessable? Stale? Overprivileged? Production-exposed? Tied to an admin identity? Those signals matter because they identify the secrets and machine identities most likely to be abused. But they do not answer the next question: what breaks if that credential is used? That answer lives in the topology around the credential. A database credential may sit on one pod and unlock one datastore, but the operational blast radius extends to every service that depends on that datastore. Some of those services never hold the credential at all. Some may not even have a secret signal to score. Want to run the same analysis on your own stack? Explore the Anyshift Graph API to query dependencies, blast radius, and production impact directly. Learn more That is where identity-local signals and topology signals become two layers of the same blast radius: one tells you why the credential is dangerous, and the other tells you how far the damage can tr
AI 资讯
Microsoft Three-Layer LLM Routing Architecture for AI Agents on AKS
Microsoft has released a reference architecture for routing agent traffic on Azure Kubernetes Service. It breaks down the issue into three key choices: which model answers a call, how the call is managed, and which GPU replica handles it. By Claudio Masolo
AI 资讯
How to safely run AI-generated code — a practical sandboxing checklist
Cross-post. Original: stellarbytecapital.com/blog/how-to-run-ai-generated-code-safely If you're building an AI agent, sooner or later it will write code and you'll have to run that code. The moment you do, you're executing something no human reviewed against your infrastructure. This is a practical checklist for doing that safely — the controls we use in production, in the order they matter. The short version: treat every piece of AI-generated code as hostile, and design so that even a full compromise of the runtime buys the attacker nothing. First, the threat model Before controls, be honest about what can go wrong when you run untrusted code: It reads or exfiltrates data belonging to other users on the same host. It reaches out to the network to leak data or pull a payload. It leaves state behind — temp files, mutated env, background threads — that corrupts the next run. It exhausts CPU, memory, or disk and takes down the shared service. It escapes the sandbox entirely via a kernel or runtime bug. "The model probably won't do that" is not a control. Design for the case where it does. The core pattern: one disposable sandbox per execution The single highest-leverage decision: run every execution in its own fresh sandbox, and destroy it after the run. Never reuse. Reuse is where most bugs and attacks live — leaked file descriptors, leftover temp files, mutated globals, a background thread from the last run. If nothing is ever reused, that entire class of problems disappears. To keep it fast, keep a warm pool of ready sandboxes and backfill each one as it's consumed. The checklist Isolation boundary — use a real boundary, not a language-level "safe eval." A container is the baseline; a microVM ( gVisor , Firecracker ) is stronger against kernel escapes. Network egress: default-deny — no outbound network by default. An escaped agent that can't reach the internet has nowhere to send data. Filesystem: read-only + ephemeral — mount inputs read-only; give a scratch space
AI 资讯
ViciDial "Campaign Has No Dialable Leads" — List & Hopper Troubleshooting
ViciDial "Campaign Has No Dialable Leads" — List & Hopper Troubleshooting Master the root causes of no dialable leads errors and regain full campaign productivity through systematic list validation, hopper configuration, and database troubleshooting. Prerequisites Before troubleshooting, ensure you have: SSH access to your ViciDial server with sudo privileges Access to the ViciDial web admin panel at /vicidial/admin.php MySQL/MariaDB command-line access to the asterisk database Understanding of basic ViciDial campaign structure (lists, dialers, agents) Root or asterisk-user permissions to check Asterisk processes Recent backups of your ViciDial database and configuration files A test campaign with known lead counts for validation The "Campaign Has No Dialable Leads" error typically appears when: The dialer attempts to initiate calls but the hopper queue is empty All records in the lead list have been exhausted or marked as non-dialable List settings conflict with campaign configuration The database connection between ViciDial and the dialer is broken Lead filtering rules remove all records from the dialable pool Understanding ViciDial List Architecture The Lead Lifecycle in ViciDial Every lead in ViciDial passes through status states that determine dialability. A lead is considered "dialable" if it matches specific criteria based on campaign and list configuration. Lead Status States: NEW — Fresh lead, never contacted QUEUE — Scheduled for dialing CALL — Currently being dialed LEFT MESSAGE — Voicemail was left CALLED — Contacted but not completed XFER — Transferred to another department XFER SEND — Pending transfer INCALL — Active call in progress CBHOLD — Callback hold status CBSCHED — Callback scheduled DNCC — Do Not Call Compiled DNCL — Do Not Call List The status field in the vicidial_list table controls whether a lead can be dialed again. Most campaigns set a maximum dial count limit to prevent redialing exhausted leads infinitely. Hopper Mechanism The ViciDial
AI 资讯
I Built a Security Tool That Proves Its Own Exploits — Then Got a Better Threat Model in the Comments
Automated offense has one embarrassing failure mode: it lies to you about winning. Point a tool at a target, and the naive success check is a substring match — see uid=0(root) in the response, call it a shell. But a service banner can print that. A tarpit can stream it on connect. And the moment your success signal is wrong, everything downstream inherits the lie: the report, the "which hosts are owned" state, the next move. You get a confident engine that's confidently wrong. Here's how I made mine prove it instead — what worked in a live run today, and the sharp reader feedback that already made the design better. The idea: make the target echo a secret it couldn't have guessed Borrow the oldest trick in authentication. Before each attempt, the orchestrator mints an unpredictable per-attempt nonce and injects it. The delivered command has to send that nonce back: import os def make_nonce() -> str: return os.urandom(12).hex() # unpredictable — a target can't guess it A result is only trusted if that exact nonce comes back, in a structured evidence line: HALO-EVIDENCE nonce=c609007176813c9110fccc27 level=shell uid=0 host= exit=0 _EVIDENCE = re.compile(r"HALO-EVIDENCE nonce=(\S+) level=(\S+)") def breach_confirmed(output, ok, *, nonce) -> bool: m = _EVIDENCE.search(output or "") return bool(ok and m and m.group(1) == nonce) Delivery is a ladder, because real hosts are inconsistent Proof is worthless if you can't deliver a payload. So delivery degrades gracefully — all stdlib socket: Reverse shell — target dials back to an ephemeral listener, announces the nonce, hands back /bin/sh. Bind shell — if egress is blocked, the target binds a shell and you connect in. Blind callback — if no interactive channel survives, the target just connects back and sends the nonce. That still proves code execution, with no usable shell. Each rung self-selects the first available interpreter (bash /dev/tcp, python3, perl, nc), so the same primitive works against arbitrary hosts, not one
AI 资讯
GitHub Introduces Default "Cooldown" Policy for Dependabot Version Updates
Instead of immediately opening pull requests when newer dependency versions are released, Dependabot now waits three days before suggesting upgrades, thus increasing the likelihood that malicious releases are identified and removed before they can be integrated. By Sergio De Simone
AI 资讯
Foreman 101: agentic coding as Kubernetes resources
Foreman is an agentic coder that runs as Kubernetes resources. You describe work as a Workload, it decomposes into tasks, agents running on your nodes pick them up, and a branch comes out the other end with something deterministic standing between that branch and your main. This is the walkthrough. Four objects to understand, an install, an agent, a verifier, and a real run. Every command and every output below is from a working cluster. The four objects Foreman is deliberately small. Almost everything you do is one of these. Agent is a worker definition: which model it talks to, which tools it may call, and what budget it gets. An Agent has a role , and the two that matter here are coder and verifier . Workload is the unit of work you actually author. It carries an intent, a repository, and which agents to use. AgenticTask is what a Workload decomposes into. You rarely write one by hand; you read them to see what is happening. FleetNode is a node that has advertised itself as able to run tasks. The scheduler matches a task's required capabilities against these. The shape of a run is: you apply a Workload, the controller synthesizes AgenticTasks, the scheduler routes each to a FleetNode whose agent can serve it, the agent runs the model in a loop with tools, and the result lands as a branch plus a verdict. The idea underneath it Worth stating plainly, because it shapes every design decision: the model is not trusted, and specifically its claim to have succeeded is not trusted. A coder agent finishes by calling a tool that says "I am done, verdict GO." Foreman treats that as a request, not a result. If the model says GO and produced no diff, the run is recorded as NO-GO. If the verifier's checks do not pass, the work does not land, no matter how confident the summary was. That is the difference between an agent that writes code and a system you can leave running. Everything else in this post is plumbing around that idea. Install Foreman ships as a Helm chart that dep
AI 资讯
Pilum: From Launch to Production-Ready in 3 Months
Github URL: https://github.com/SID-Technologies/Pilum In December 2025, I open-sourced Pilum , a multi-cloud deployment CLI that deploys to Cloud Run, Lambda, Azure, Cloudflare Pages, npm, Homebrew, and Docker Hub from a single pilum.yaml . The announcement post covered the architecture: recipes, ingredients, handlers, wave-based execution. That was the "it compiles and the tests pass" version. Three months and 40+ pull requests later, Pilum deploys all of SID Technologies , platform-core, Torch, Statio, every website, every npm package, and itself. This post is about everything that broke between "it works" and "it ships production software." ( Update: * there's now a seven-months-in addendum at the bottom. It's mostly about what stopped breaking.)* The Timeline Dec 2, 2025 : First commit. Baseline CLI with recipe system. (#1) Dec 4 : Homebrew release workflow. Pilum dogfoods its own deployment. (#2-#4) Dec 31 : Service graph, --only-changed , file embedding support. The "I need this for real" features. (#22-#24) Jan 3-12 : Documentation and bug fixes. The quiet "oh, this doesn't actually work" phase. (#25-#29) Feb 6-7 : The big feature sprint — 8 features in 48 hours. Wave deployments, npm recipe, Cloudflare Pages, Azure Container Apps, Cloud Run Jobs, environment variables, JSON output, history command. (#30-#38) Feb 8-12 : The big fix sprint — YAML parsing, package manager issues, build failures, error swallowing, GCP secrets, Cloudflare execution. Everything from the feature sprint broke something. (#42-#49) Feb 24 : Security hardening and npm publishing fixes. (#51-#53) Mar-Apr : Memory-based worker allocation, wave ordering bug, orchestrator rewrite. The "I thought this was done" phase. (#58-#62) The pattern is clear: features ship fast, fixes ship faster, and the real bugs show up a month later. Wave-Based Deployments Were Broken Wave-based deployment was the headline feature in #31. Services declare dependencies, Pilum builds a dependency graph, topological
AI 资讯
Cómo montar un motor de contenidos que no te arruine (julio 2026)
Cómo montar un motor de contenidos que no te arruine (julio 2026) Si sigues pagando 300 euros al mes por herramientas "todo en uno" de marketing, estás tirando el dinero. A mediados de 2026, la tecnología para automatizar ha bajado tanto de precio que los costes de infraestructura de contenidos son casi ridículos. La clave no es la herramienta cara, es conectar piezas pequeñas con APIs baratas. Aquí tienes cómo tengo montado mi flujo de trabajo ahora mismo. La pila tecnológica (el stack) Para automatizar sin gastar, olvida las plataformas de marketing tipo HubSpot o plataformas cerradas. Mi setup actual es este: Cerebro: Claude 3.5 Sonnet (vía API). Es mejor razonando que GPT-4o para tono editorial. Orquestador: n8n (corriendo en una VPS de 5 euros al mes en Hetzner). Base de datos: Notion (vía API para gestionar el calendario). Distribución: Ghost para el blog y la API de LinkedIn/X para el alcance. Coste total: Menos de 15 euros al mes. Paso 1: El disparador (el calendario en Notion) No uses un Excel. Usa una base de datos de Notion con cuatro columnas: Estado , Título , Prompt_Contexto y Fecha_Publicación . Cuando cambias el estado de "Borrador" a "Listo para generar", el webhook de n8n se dispara. Aquí es donde empieza el ahorro. No envías toda la base de datos, envías solo el registro nuevo. Paso 2: El prompt como código, no como texto La mayoría de la gente comete el error de pedirle a la IA: "escribe un post sobre X". Sale basura genérica. En 2026, si no das contexto, el contenido no posiciona ni recibe interacción. En tu nodo de n8n, construye el prompt de forma dinámica. Así es como envío la estructura a la API: { "model" : "claude-3-5-sonnet-20260620" , "system" : "Eres un redactor técnico senior especializado en SaaS B2B. Tu estilo es directo, sin paja, sin adjetivos innecesarios. Evitas los clichés de marketing de 2024. Tu objetivo es educar, no vender." , "messages" : [ { "role" : "user" , "content" : "Escribe un artículo corto basado en este punto clav
AI 资讯
SRE Playbook: A Guide to Discover and Catalog Non-Human Identities (NHI)
As a site reliability engineer in a global company, I'm running a modern (well, relatively modern, to be honest and modest) cloud-native stack: HashiCorp Vault as the secret manager, workloads on Kubernetes clusters in AWS (EKS), and development workflows automated through Jenkins (legacy) and GitLab CI. This setup is, quite likely, familiar to you — it's the normal playbook in the cloud-native era. In theory, we have the right tools for both security and efficiency: After all, we have a state-of-the-art secret manager integrated with everything. But in reality, it's far from the truth. See if you resonate with the following scenarios: Scenario A: A new colleague just joined the team. Manager: "Your initial password to log in to your corporate account came to me via email, but since you can't log in to your mail account just yet, here, take a picture of my screen." (In some companies, taking a picture of a computer monitor would get you fired, I'm not kidding.) Scenario B: A developer needs a temp password to access a database. Dev: "Where is the newly created temporary password? Need it for debugging." Ops: "In the Vault." Dev: "I can't access Vault." Ops: "No, you can't. It's not safe to open UI access to Vault. Corporate policy." Dev: "Then how can I get the password?" Ops: "Well... Technically, the password isn't in the Vault. There is a Jenkins pipeline that calls the Vault API to generate a temp password, then stores it in Jenkins secrets. You need to request access to the corresponding Jenkins pipeline, trigger it, then get the secrets from Jenkins." Dev: "Why on earth do we store secrets in Jenkins when we have Vault, which we aren't allowed to use?" Ops: "Corporate policy, just told you." Scenario C: A new ops team member needs to update a certificate for a service running in production for the first time. Ops: "Where is the old cert?" Mentor: "In K8s as a secret." Ops: "Where is the cluster?" Mentor: "In AWS." Ops: "How do I access that?" Mentor: "You need