<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Priya Ranjan Sahu</title>
    <description>The latest articles on DEV Community by Priya Ranjan Sahu (@priyaranjansahu).</description>
    <link>https://dev.to/priyaranjansahu</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4084807%2F9b8bc662-32b2-42a7-8027-86c7a465f8d7.png</url>
      <title>DEV Community: Priya Ranjan Sahu</title>
      <link>https://dev.to/priyaranjansahu</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/priyaranjansahu"/>
    <language>en</language>
    <item>
      <title>I got tired of surprise AWS bills, so I open-sourced a Multi-Cloud FinOps Engine.</title>
      <dc:creator>Priya Ranjan Sahu</dc:creator>
      <pubDate>Fri, 28 Aug 2026 15:20:48 +0000</pubDate>
      <link>https://dev.to/priyaranjansahu/i-got-tired-of-surprise-aws-bills-so-i-open-sourced-a-multi-cloud-finops-engine-1ckc</link>
      <guid>https://dev.to/priyaranjansahu/i-got-tired-of-surprise-aws-bills-so-i-open-sourced-a-multi-cloud-finops-engine-1ckc</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fedrdc8loppifz8dsdwsx.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fedrdc8loppifz8dsdwsx.jpg" alt=" " width="800" height="447"&gt;&lt;/a&gt;&lt;br&gt;
Let's be honest.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cloud billing is broken.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you're running an engineering team across &lt;strong&gt;AWS, GCP, and Azure&lt;/strong&gt;, trying to figure out exactly what's costing you money can sometimes feel like you need a PhD in spreadsheet management.&lt;/p&gt;

&lt;p&gt;By the time you realize that a forgotten database cluster has been burning &lt;strong&gt;$50 a day&lt;/strong&gt;, the month is already over and the invoice has already been generated.&lt;/p&gt;

&lt;p&gt;I got tired of this.&lt;/p&gt;

&lt;p&gt;I wanted a simple way to just ping a single API and ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"Am I spending money on something stupid today?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So, I built one.&lt;/p&gt;

&lt;p&gt;And today, I'm &lt;strong&gt;open-sourcing it.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Meet the Multi-Cloud FinOps Engine
&lt;/h2&gt;

&lt;p&gt;I built a unified &lt;strong&gt;Python + FastAPI&lt;/strong&gt; engine that connects to your cloud accounts, normalizes billing data into the &lt;strong&gt;FOCUS 1.0&lt;/strong&gt; standard, and uses local machine learning to detect cost anomalies.&lt;/p&gt;

&lt;p&gt;The goal is simple:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One API. Multiple clouds. One normalized view of your cloud spend.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here's what I prioritized while building it.&lt;/p&gt;
&lt;h2&gt;
  
  
  1. No External SaaS
&lt;/h2&gt;

&lt;p&gt;You shouldn't have to send sensitive billing telemetry to a third-party startup just to understand your own cloud spending.&lt;/p&gt;

&lt;p&gt;The engine is designed to be &lt;strong&gt;self-hosted&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Your billing data stays within your infrastructure.&lt;/p&gt;

&lt;p&gt;No external FinOps SaaS dependency.&lt;/p&gt;
&lt;h2&gt;
  
  
  2. True Multi-Cloud Support
&lt;/h2&gt;

&lt;p&gt;The engine natively works with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;AWS Cost Explorer&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GCP BigQuery Billing Exports&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Azure Cost Management&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of maintaining three completely different billing implementations, the engine brings the data into a common model.&lt;/p&gt;

&lt;p&gt;That makes it much easier to answer questions like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which cloud is costing us the most?&lt;/li&gt;
&lt;li&gt;Which service increased spending this week?&lt;/li&gt;
&lt;li&gt;Where are our biggest cost anomalies?&lt;/li&gt;
&lt;li&gt;What resources are unexpectedly expensive?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  3. FOCUS 1.0 Normalization
&lt;/h2&gt;

&lt;p&gt;One of the biggest challenges with multi-cloud FinOps is that every cloud provider represents cost data differently.&lt;/p&gt;

&lt;p&gt;AWS, GCP, and Azure all have different billing schemas, dimensions, terminology, and metadata.&lt;/p&gt;

&lt;p&gt;The engine normalizes the data into the &lt;strong&gt;FOCUS 1.0&lt;/strong&gt; standard so downstream applications don't need completely different logic for every cloud provider.&lt;/p&gt;

&lt;p&gt;This gives you a consistent foundation for analytics and automation.&lt;/p&gt;
&lt;h2&gt;
  
  
  4. Zero Memory Spikes During Large Exports
&lt;/h2&gt;

&lt;p&gt;Billing datasets can become &lt;strong&gt;huge&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you're dealing with millions of rows, loading the entire dataset into memory before returning it is a great way to make your API server unhappy.&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;v1.1.0&lt;/code&gt; release, I implemented FastAPI &lt;code&gt;StreamingResponse&lt;/code&gt; generators for large billing exports.&lt;/p&gt;

&lt;p&gt;Instead of doing this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Load everything → Store everything in RAM → Return response
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the API can stream the data progressively:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Fetch → Generate → Stream → Repeat
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allows the engine to handle &lt;strong&gt;millions of rows of billing telemetry&lt;/strong&gt; without unnecessarily spiking RAM usage.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Non-Blocking Machine Learning
&lt;/h2&gt;

&lt;p&gt;Running Scikit-Learn models such as &lt;strong&gt;Isolation Forest&lt;/strong&gt; against large datasets can become expensive.&lt;/p&gt;

&lt;p&gt;And if you run CPU-heavy workloads directly inside your FastAPI event loop, you can quickly turn your asynchronous API into a bottleneck.&lt;/p&gt;

&lt;p&gt;To avoid that, I routed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Machine learning workloads&lt;/li&gt;
&lt;li&gt;External cloud SDK calls&lt;/li&gt;
&lt;li&gt;Other blocking operations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;through &lt;strong&gt;ThreadPools&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The goal is to keep the FastAPI event loop responsive while the heavy work happens outside the main execution path.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Architecture
&lt;/h2&gt;

&lt;p&gt;At a high level, the flow looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                   ┌─────────────────────┐
                   │      API Client     │
                   └──────────┬──────────┘
                              │
                              ▼
                   ┌─────────────────────┐
                   │     FastAPI API     │
                   └──────────┬──────────┘
                              │
              ┌───────────────┼────────────────┐
              │               │                │
              ▼               ▼                ▼
        ┌──────────┐    ┌──────────┐    ┌──────────┐
        │   AWS    │    │   GCP    │    │  Azure   │
        │   Cost   │    │ BigQuery │    │   Cost   │
        │ Explorer │    │ Billing  │    │Management│
        └────┬─────┘    └────┬─────┘    └────┬─────┘
             │               │                │
             └───────────────┼────────────────┘
                             ▼
                  ┌─────────────────────┐
                  │  FOCUS 1.0          │
                  │  Normalization      │
                  └──────────┬──────────┘
                             │
                  ┌──────────┴──────────┐
                  ▼                     ▼
          ┌──────────────┐      ┌──────────────┐
          │ Cost Analysis│      │ ML Anomaly   │
          │              │      │ Detection    │
          └──────────────┘      └──────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The idea is to keep the provider-specific logic at the ingestion layer and expose a consistent interface to everything above it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Stack
&lt;/h2&gt;

&lt;h3&gt;
  
  
  API
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;FastAPI&lt;/li&gt;
&lt;li&gt;Pydantic v2&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Data &amp;amp; Machine Learning
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Pandas&lt;/li&gt;
&lt;li&gt;Scikit-Learn&lt;/li&gt;
&lt;li&gt;Isolation Forest&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Infrastructure
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Docker&lt;/li&gt;
&lt;li&gt;Kubernetes&lt;/li&gt;
&lt;li&gt;KEDA for autoscaling&lt;/li&gt;
&lt;li&gt;Terraform&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The entire system is designed with containerized and Kubernetes-based deployments in mind.&lt;/p&gt;

&lt;h2&gt;
  
  
  The "Open Core" Model
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;core aggregation API&lt;/strong&gt; and &lt;strong&gt;FOCUS 1.0 normalization&lt;/strong&gt; are completely free and open-source.&lt;/p&gt;

&lt;p&gt;For enterprise teams that need more advanced capabilities, I've implemented a cryptographic &lt;strong&gt;RS256 JWT license gate&lt;/strong&gt; for the advanced rightsizing engines.&lt;/p&gt;

&lt;p&gt;The idea is to keep the foundation open while providing a path for organizations that need enterprise-level FinOps capabilities.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I Built This
&lt;/h2&gt;

&lt;p&gt;Cloud cost optimization shouldn't require manually jumping between:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AWS Cost Explorer&lt;/li&gt;
&lt;li&gt;GCP Billing&lt;/li&gt;
&lt;li&gt;Azure Cost Management&lt;/li&gt;
&lt;li&gt;Spreadsheets&lt;/li&gt;
&lt;li&gt;Dashboards&lt;/li&gt;
&lt;li&gt;Custom scripts&lt;/li&gt;
&lt;li&gt;And five different browser tabs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I wanted something that could answer a much simpler question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"What's costing me money, and is anything unusual happening right now?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's the problem I'm trying to solve.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try It Yourself
&lt;/h2&gt;

&lt;p&gt;The project is open-source, and I'd genuinely love feedback.&lt;/p&gt;

&lt;p&gt;You can check out the repository here:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/priyaranjan-sahu/multi-cloud-finops" rel="noopener noreferrer"&gt;https://github.com/priyaranjan-sahu/multi-cloud-finops&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you're running AWS, GCP, or Azure, try it against your own environment.&lt;/p&gt;

&lt;p&gt;I'd especially love feedback on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Architecture&lt;/li&gt;
&lt;li&gt;FOCUS 1.0 normalization&lt;/li&gt;
&lt;li&gt;Multi-cloud cost modeling&lt;/li&gt;
&lt;li&gt;Anomaly detection&lt;/li&gt;
&lt;li&gt;Performance&lt;/li&gt;
&lt;li&gt;Kubernetes deployment&lt;/li&gt;
&lt;li&gt;FinOps workflows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And, of course, &lt;strong&gt;tear the codebase apart.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's what open source is for. 🙂&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Cloud waste rarely comes from one massive mistake.&lt;/p&gt;

&lt;p&gt;It's usually a collection of small things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An unattached resource&lt;/li&gt;
&lt;li&gt;An oversized instance&lt;/li&gt;
&lt;li&gt;An idle database&lt;/li&gt;
&lt;li&gt;A forgotten environment&lt;/li&gt;
&lt;li&gt;A test cluster that nobody shut down&lt;/li&gt;
&lt;li&gt;A resource that quietly grew over time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Individually, they don't look like much.&lt;/p&gt;

&lt;p&gt;Together, they can become a surprisingly large bill.&lt;/p&gt;

&lt;p&gt;So I'd love to hear from you:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's the worst cloud billing horror story you've experienced?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Mine was leaving an &lt;strong&gt;unattached Elastic IP running for six months.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;🙃&lt;/p&gt;

</description>
      <category>python</category>
      <category>devops</category>
      <category>aws</category>
      <category>gcp</category>
    </item>
    <item>
      <title>One storage security audit suite for Azure, AWS, and GCP</title>
      <dc:creator>Priya Ranjan Sahu</dc:creator>
      <pubDate>Wed, 19 Aug 2026 10:38:54 +0000</pubDate>
      <link>https://dev.to/priyaranjansahu/one-storage-security-audit-suite-for-azure-aws-and-gcp-cml</link>
      <guid>https://dev.to/priyaranjansahu/one-storage-security-audit-suite-for-azure-aws-and-gcp-cml</guid>
      <description>&lt;p&gt;Every cloud environment I've touched has the same two storage problems: a bucket someone made public and forgot, and a storage account that should be behind a private endpoint but isn't. The checks differ slightly per provider, but the question is always the same — "is this storage reachable by someone who shouldn't see it?"&lt;/p&gt;

&lt;p&gt;I got tired of answering that question with ad-hoc scripts that died in one environment and were rewritten in the next. So I built one suite that covers all three clouds and writes every result to the same CSV/JSON shape.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it checks
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;AWS (S3)&lt;/strong&gt; — the three ways a bucket becomes public:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Public Access Block fully enabled&lt;/li&gt;
&lt;li&gt;Bucket policy reported as &lt;code&gt;IsPublic&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;ACL grants to &lt;code&gt;AllUsers&lt;/code&gt; / &lt;code&gt;AuthenticatedUsers&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Plus a security-config audit for default encryption (SSE-S3/SSE-KMS) and versioning.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GCP (Cloud Storage)&lt;/strong&gt; — IAM bindings to &lt;code&gt;allUsers&lt;/code&gt; / &lt;code&gt;allAuthenticatedUsers&lt;/code&gt;, uniform bucket-level access, and public access prevention.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Azure (Storage Accounts)&lt;/strong&gt; — accounts with and without Private Endpoints, plus TLS version, secure transfer, and public network access posture.&lt;/p&gt;

&lt;p&gt;Everything is read-only. No module creates, modifies, or deletes anything — you run it, get a report, fix what it flags.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# AWS: only the public buckets, as JSON&lt;/span&gt;
python aws/s3/audit-public-buckets/audit_public_buckets.py &lt;span class="nt"&gt;--only-public&lt;/span&gt; &lt;span class="nt"&gt;--format&lt;/span&gt; json &lt;span class="nt"&gt;--output-file&lt;/span&gt; public.json

&lt;span class="c"&gt;# GCP: security configuration matrix&lt;/span&gt;
python gcp/storage/audit-security-config/audit_bucket_security.py &lt;span class="nt"&gt;--project&lt;/span&gt; my-project &lt;span class="nt"&gt;--output-file&lt;/span&gt; compliance.csv

&lt;span class="c"&gt;# Azure: storage accounts with no private endpoint&lt;/span&gt;
./azure/storage/audit-missing-private-endpoints/audit-storage-without-pe.ps1 &lt;span class="nt"&gt;-OutputPath&lt;/span&gt; exposed.csv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Azure side also ships Bash and KQL variants so you can run the same check from Resource Graph in the portal.&lt;/p&gt;

&lt;h2&gt;
  
  
  The report contract
&lt;/h2&gt;

&lt;p&gt;Every module writes the same shape — CSV or JSON — with a boolean "finding" column you actually act on:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Provider&lt;/th&gt;
&lt;th&gt;Finding column&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;AWS public buckets&lt;/td&gt;
&lt;td&gt;&lt;code&gt;is_public&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AWS / GCP security config&lt;/td&gt;
&lt;td&gt;&lt;code&gt;hardened&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GCP public IAM&lt;/td&gt;
&lt;td&gt;&lt;code&gt;public&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Azure (no PE)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;PrivateEndpointCount == 0&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Summaries go to stderr, so stdout stays clean for automation. Redacted example outputs for every module are in &lt;a href="https://github.com/priyaranjan-sahu/multi-cloud-automation-scripts/tree/main/docs/samples" rel="noopener noreferrer"&gt;&lt;code&gt;docs/samples/&lt;/code&gt;&lt;/a&gt;, and the full field contract is in &lt;a href="https://github.com/priyaranjan-sahu/multi-cloud-automation-scripts/blob/main/docs/report-format.md" rel="noopener noreferrer"&gt;&lt;code&gt;docs/report-format.md&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The bug that cost me half a day
&lt;/h2&gt;

&lt;p&gt;The AWS and GCP scripts in each provider are named the same — &lt;code&gt;audit_public_buckets.py&lt;/code&gt;, &lt;code&gt;audit_bucket_security.py&lt;/code&gt;. That's fine until your test files import both. Python imports by module name, so once pytest cached the AWS version, the GCP tests silently imported the wrong code and failed with the most confusing TypeError.&lt;/p&gt;

&lt;p&gt;The fix was loading the modules by explicit file path instead of leaning on &lt;code&gt;sys.path&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;spec&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;importlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;util&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;spec_from_file_location&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;module&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;importlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;util&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;module_from_spec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exec_module&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Half a day, gone, over a naming collision.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keeping it honest
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pester&lt;/strong&gt; validates the Azure modules (parse, parameters, read-only guarantees)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;pytest&lt;/strong&gt; (mocked cloud clients) covers the AWS/GCP modules&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CI&lt;/strong&gt; runs PSScriptAnalyzer, ShellCheck, ruff, markdownlint, and yamllint on every push&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test coverage sits at 85%&lt;/strong&gt; and is published via Codecov&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first CI run failed in four jobs at once — the lesson being that lint rules move under you (a newer PSScriptAnalyzer started flagging &lt;code&gt;Write-Host&lt;/code&gt; as a warning I'd never seen before).&lt;/p&gt;

&lt;h2&gt;
  
  
  Where it lives
&lt;/h2&gt;

&lt;p&gt;The whole thing is free and open source:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/priyaranjan-sahu/multi-cloud-automation-scripts" rel="noopener noreferrer"&gt;https://github.com/priyaranjan-sahu/multi-cloud-automation-scripts&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you manage storage across more than one cloud, it's probably a better starting point than whatever script you were about to rewrite for the fifth time. PRs and issues welcome.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>security</category>
      <category>cloud</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
