Skip to content

feat: add report command, webhook notifications, PyPI metadata, release automation, and idle Azure checks - #24

Merged
raphgm merged 1 commit into
raphgm:mainfrom
Steeve-devops:feat/resolve-seven-issues
Sep 22, 2026
Merged

raphgm merged 1 commit into
raphgm:mainfrom
Steeve-devops:feat/resolve-seven-issues

Conversation

@Steeve-devops

Copy link
Copy Markdown
Contributor

Summary

This PR addresses a set of small, self-contained improvements and issue resolutions across the project:

  • adds HTML findings report output
  • adds Slack/webhook notification support for findings
  • adds minimal PyPI metadata readiness
  • adds PyPI publish step to the release workflow
  • adds idle Azure API Management, Fleet Manager, and Managed HSM checks

Validation

  • . [100%]
    1 passed in 1.55s
  • . [100%]
    1 passed in 1.43s
  • . [100%]
    1 passed in 0.00s
  • . [100%]
    1 passed in 0.01s
  • .. [100%]
    2 passed in 0.32s
  • .. [100%]
    2 passed in 0.30s
  • .. [100%]
    2 passed in 0.30s

Notes

These changes are intentionally scoped to low-risk, testable improvements that align with the existing project patterns and issue backlog.

@raphgm
raphgm merged commit 044a9ca into raphgm:main Sep 22, 2026
1 check failed
raphgm added a commit that referenced this pull request Sep 22, 2026
….toml bug

PR #24 (merged directly to main) added idle_apim/idle_fleet_manager/
idle_managed_hsm as SQL policies + synthetic-data tests only -- no
source/extraction files, no runner.py registration. All three were
completely non-functional (cloudcost sync had no source plugin to
call), and the hardcoded prices were fabricated and wrong:

- APIM: flat $30/month for every tier (Basic/Standard/Premium) --
  real prices are $0.2016/hr, $0.9407/hr, and much higher for
  Premium, confirmed live via the Retail Prices API. Off by 3x-65x
  depending on tier.
- Managed HSM: flat $10.00 -- real price is $3.20/hour ($2,336/month),
  confirmed via Microsoft's own published Key Vault pricing page since
  the Retail Prices API has no queryable meter for this product (same
  real gap already documented in idle_load_balancers.sql). Off by
  ~233x.
- Fleet Manager: flat $30/month -- Azure Kubernetes Fleet Manager is
  explicitly FREE per Microsoft's own pricing page ('Azure Kubernetes
  Fleet Manager resource is free to use'). The real cost is the hub
  cluster's own AKS node (Standard_DS3_v2 by default), which this
  fix now checks and prices live instead.

Also fixed a separate, more severe bug from the same PR: pyproject.toml
had its 'dependencies' array accidentally nested inside
[project.urls], which only accepts string values -- this broke
Usage:
  pip <command> [options]

Commands:
  install                     Install packages.
  lock                        Generate a lock file.
  download                    Download packages.
  uninstall                   Uninstall packages.
  freeze                      Output installed packages in requirements format.
  inspect                     Inspect the python environment.
  list                        List installed packages.
  show                        Show information about installed packages.
  check                       Verify installed packages have compatible
dependencies.
  config                      Manage local and global configuration.
  search                      Search PyPI for packages.
  cache                       Inspect and manage pip's wheel cache.
  index                       Inspect information available from package
indexes.
  wheel                       Build wheels from your requirements.
  hash                        Compute hashes of package archives.
  completion                  A helper command used for command completion.
  debug                       Show information useful for debugging.
  help                        Show help for commands.

General Options:
  -h, --help                  Show help.
  --debug                     Let unhandled exceptions propagate outside the
                              main subroutine, instead of logging them to
                              stderr.
  --isolated                  Run pip in an isolated mode, ignoring
                              environment variables and user configuration.
  --require-virtualenv        Allow pip to only run in a virtual environment;
                              exit with an error otherwise.
  --python <python>           Run pip with the specified Python interpreter.
  -v, --verbose               Give more output. Option is additive, and can be
                              used up to 3 times.
  -V, --version               Show version and exit.
  -q, --quiet                 Give less output. Option is additive, and can be
                              used up to 3 times (corresponding to WARNING,
                              ERROR, and CRITICAL logging levels).
  --log <path>                Path to a verbose appending log.
  --no-input                  Disable prompting for input.
  --keyring-provider <keyring_provider>
                              Enable the credential lookup via the keyring
                              library if user input is allowed. Specify which
                              mechanism to use [auto, disabled, import,
                              subprocess]. (default: auto)
  --proxy <proxy>             Specify a proxy in the form
                              scheme://[user:passwd@]proxy.server:port.
  --retries <retries>         Maximum attempts to establish a new HTTP
                              connection. (default: 5)
  --timeout <sec>             Set the socket timeout (default 15 seconds).
  --exists-action <action>    Default action when a path already exists:
                              (s)witch, (i)gnore, (w)ipe, (b)ackup, (a)bort.
  --trusted-host <hostname>   Mark this host or host:port pair as trusted,
                              even though it does not have valid or any HTTPS.
  --cert <path>               Path to PEM-encoded CA certificate bundle. If
                              provided, overrides the default. See 'SSL
                              Certificate Verification' in pip documentation
                              for more information.
  --client-cert <path>        Path to SSL client certificate, a single file
                              containing the private key and the certificate
                              in PEM format.
  --cache-dir <dir>           Store the cache data in <dir>.
  --no-cache-dir              Disable the cache.
  --disable-pip-version-check
                              Don't periodically check PyPI to determine
                              whether a new version of pip is available for
                              download. Implied with --no-
                              index.
  --no-color                  Suppress colored output.
  --use-feature <feature>     Enable new functionality, that may be backward
                              incompatible.
  --use-deprecated <feature>  Enable deprecated functionality, that will be
                              removed in the future.
  --resume-retries <resume_retries>
                              Maximum attempts to resume or restart an
                              incomplete download. (default: 5) for EVERY fresh clone of the repo (confirmed: 'invalid type:
sequence, expected a string'). Moved dependencies back under
[project].

All three checks now have real source files (registered in
runner.py), live per-resource pricing, and were verified against real
Azure resources created for this fix:
- A real Developer-tier APIM instance -> $48.03/month flagged
  (correct: 0.0658 * 730).
- A real Standard_B1 Managed HSM -> $2,336/month flagged (correct:
  3.20 * 730) -- also caught and fixed a second real bug during this
  verification: the source read 'properties.skuName' which doesn't
  exist; the real field is 'sku.name', silently returning None and
  a $0 price until fixed.
- A real Fleet hub with 0 member clusters -> $213.89/month flagged
  (correct: Standard_DS3_v2 live price * 730).

Updated all three test files to match the corrected schema
(hourly_price/hourly_price_per_unit columns) and real prices, plus
added tests confirming a zero/unrecognized price never produces a
false-positive finding.
raphgm added a commit that referenced this pull request Sep 22, 2026
Real, pre-existing gap found via an audit prompted by the PR #24
incident: rightsizing_utilization.sql and its azure.vm_metrics source
were both real and correctly registered, but no cloudcost.*.yml
existed for this check -- nobody could actually run it, unlike every
other check in this project which ships a runnable real-verification
config.

This check needs two joined sources (VM metrics AND a real Cost
Management export, joined on resource_id) since it grades utilization
against real billed_cost, not metrics alone -- more involved than a
single-source check, likely why it was missed originally.

Also found and fixed a naming mismatch while building this: the
source registers itself as 'azure.vm_metrics', not 'azure.metrics' as
the module's own filename would suggest.

Verified against real data: 24 real VM metric rows (cost-compare-3day-rg)
joined with 754 real Cost Management export line items -> 1 real
finding, $0.18 impact for the one VM in scope.
raphgm added a commit that referenced this pull request Sep 24, 2026
…ublish

Version bump reflects everything since v0.1.0: 3 fabricated PR #24
checks fixed with real pricing, the rightsizing_utilization missing
pipeline config, a new idle Health Data Services FHIR check, a 10-row
stale README fix, the PyPI rename to cloudcost-finops, and the new
`cloudcost remediate` command.

Also fixed a real bug found while reviewing the release workflow for
this bump: the PyPI publish step runs inside the 3-OS build matrix
with no OS guard, so on an actual release it would try to upload the
same version 3 times -- PyPI accepts the first and rejects the
2nd/3rd as a duplicate, failing 2 of the 3 binary-build jobs. Now
publishes once, from ubuntu-latest, and skips (instead of failing the
whole job) if PYPI_API_TOKEN isn't set yet.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants