Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .claude/settings.local.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"permissions": {
"allow": [
"Bash(ssh:*)",
"Bash(git checkout:*)",
"Bash(git add:*)",
"Bash(git commit:*)",
"Bash(GIT_SSH_COMMAND=\"ssh -i ~/.ssh/id_rsa -o IdentitiesOnly=yes\" git push:*)",
"WebFetch(domain:raw.githubusercontent.com)",
"WebFetch(domain:github.com)",
"WebSearch",
"Bash(gh pr:*)",
"Bash(curl:*)"
]
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Local-only Claude settings file committed to repository

Medium Severity

.claude/settings.local.json is a machine-specific local settings file that is not meant to be committed to version control. Per Claude Code documentation, the settings.local.json variant is for personal overrides and the .gitignore does not exclude it. The shared, committable equivalent is .claude/settings.json. This file includes personal permission grants (e.g., SSH key paths) that are specific to one developer's environment and won't work for other team members.

Fix in Cursor Fix in Web

30 changes: 30 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
name: Bug Report
about: Report a bug or unexpected behavior in this module
title: '[BUG] '
labels: bug
assignees: ''
---

## Describe the Bug
A clear and concise description of what the bug is.

## Steps to Reproduce
1. Module configuration used (sanitize any secrets)
2. Command run (e.g. `terraform apply`)
3. See error

## Expected Behavior
What you expected to happen.

## Actual Behavior
What actually happened. Include the full error message/stack trace if applicable.

## Environment
- Terraform / OpenTofu version:
- Provider version (`digitalocean/digitalocean`):
- Module version / git ref:
- OS:

## Additional Context
Any other context, logs, or screenshots that might help diagnose the issue.
8 changes: 8 additions & 0 deletions .github/ISSUE_TEMPLATE/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
blank_issues_enabled: false
contact_links:
- name: CloudDrove Community
url: https://clouddrove.com
about: For general questions and community support.
- name: DigitalOcean Terraform Provider Docs
url: https://registry.terraform.io/providers/digitalocean/digitalocean/latest/docs
about: Official DigitalOcean Terraform provider documentation.
22 changes: 22 additions & 0 deletions .github/ISSUE_TEMPLATE/feature_request.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
name: Feature Request
about: Suggest a new feature or enhancement for this module
title: '[FEATURE] '
labels: enhancement
assignees: ''
---

## Summary
A clear and concise description of the feature you're requesting.

## Problem / Motivation
Describe the problem this feature would solve or the use case it enables.

## Proposed Solution
Describe the solution you'd like. Include example Terraform/OpenTofu configuration if possible.

## Alternatives Considered
List any alternative approaches or workarounds you've already tried.

## Additional Context
Any other context, links to upstream provider docs, or related issues.
6 changes: 3 additions & 3 deletions .github/workflows/automerge.yml
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
name: Auto merge
on:
pull_request:
permissions:
permissions:
contents: write
checks: read
pull-requests: write
jobs:
auto-merge:
uses: clouddrove/github-shared-workflows/.github/workflows/auto_merge.yml@521761c1a5cf68d919980a2ed84b755182aeabfe # pinned to latest
uses: clouddrove/github-shared-workflows/.github/workflows/auto_merge.yml@88efd7724e007c8f721a219498be29e0c9ad471b # pinned to latest
with:
azure_cloud: true
tfchecks_azure: '["tf-lint / tflint"]'
secrets:
GITHUB: ${{ secrets.GITHUB }}
GITHUB: ${{ secrets.GITHUB }}
8 changes: 4 additions & 4 deletions .github/workflows/checkov.yml
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
name: Security Scan

on:
pull_request:
on:
pull_request:
branches: [master]
types: [opened, synchronize]

jobs:
jobs:
checkov:
uses: clouddrove/github-shared-workflows/.github/workflows/checkov.yml@f6cad30db3bfad5fc248a08ab65ac82eb8dbcb82 # pinned to latest
with:
directory: '.'
continue_on_error: 'true'
skip_check: 'CKV_TF_1'
skip_check: 'CKV_TF_1'
2 changes: 1 addition & 1 deletion .github/workflows/gitleaks-pr-scan.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ permissions:

jobs:
gitleaks:
uses: clouddrove/github-shared-workflows/.github/workflows/gitleaks-pr-scan.yml@521761c1a5cf68d919980a2ed84b755182aeabfe
uses: clouddrove/github-shared-workflows/.github/workflows/gitleaks-pr-scan.yml@62909fc10e105bba5cba4ff73b03c020b97789d4 # pinned to latest
secrets: inherit
9 changes: 5 additions & 4 deletions .github/workflows/pr_checks.yml
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
name: 'PR Validation'
name: PR Validation

on:
pull_request_target:
pull_request_target:
types:
- opened
- edited
- synchronize
- reopened

jobs:
pre-validation:
pr-validation:
if: github.actor != 'dependabot[bot]'
uses: clouddrove/github-shared-workflows/.github/workflows/pr_checks.yml@f6cad30db3bfad5fc248a08ab65ac82eb8dbcb82 # pinned to latest
secrets: inherit
with:
subjectPattern: '^.+$'
subjectPattern: '^.+$'
8 changes: 4 additions & 4 deletions .github/workflows/stale_pr.yml
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
name: 'Mark or close stale issues and PRs'
name: Mark or close stale issues and PRs

on:
on:
schedule:
- cron: '0 0 * * 5' # Runs every Friday midnight
- cron: '0 0 * * 5' # Runs every Friday midnight
workflow_dispatch:

jobs:
call-shared-stale:
uses: clouddrove/github-shared-workflows/.github/workflows/stale_pr.yml@f6cad30db3bfad5fc248a08ab65ac82eb8dbcb82 # pinned to latest
with:
with:
days-before-issue-stale: 30
days-before-pr-stale: 30
days-before-issue-close: 10
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/tag-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ on:
pull_request:
types: [closed]

jobs:
jobs:
release:
uses: clouddrove/github-shared-workflows/.github/workflows/tag-release.yml@f6cad30db3bfad5fc248a08ab65ac82eb8dbcb82 # pinned to latest
with:
target_branch: master
secrets:
GITHUB: ${{ secrets.GITHUB_TOKEN }}
GITHUB: ${{ secrets.GITHUB_TOKEN }}
5 changes: 3 additions & 2 deletions .github/workflows/tf-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ jobs:
complete-example:
uses: clouddrove/github-shared-workflows/.github/workflows/stf-checks.yml@521761c1a5cf68d919980a2ed84b755182aeabfe # pinned to latest
with:
provider: digitalocean
working_directory: './_examples/complete/'

# Seperate Job for TFlint workflow call
# Separate job for TFlint workflow call
tf-lint:
uses: clouddrove/github-shared-workflows/.github/workflows/tf-lint.yml@f6cad30db3bfad5fc248a08ab65ac82eb8dbcb82 # pinned to latest
secrets:
secrets:
GITHUB: ${{ secrets.GITHUB }}
2 changes: 1 addition & 1 deletion .github/workflows/tflint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ on:

jobs:
tf-lint:
uses: clouddrove/github-shared-workflows/.github/workflows/tf-lint.yml@c615ea7ef3e5beba98a335bf9acce8e67e03c755 # pinned to latest
uses: clouddrove/github-shared-workflows/.github/workflows/tf-lint.yml@master
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Workflow uses unpinned branch ref instead of SHA

High Severity

The tf-lint.yml workflow reference was changed from a pinned SHA (@c615ea7...) to @master, making it vulnerable to supply-chain attacks if the upstream repository is compromised. Every other workflow in this repository uses pinned SHAs — and the exact same tf-lint.yml workflow is pinned to @f6cad30db3bfad5fc248a08ab65ac82eb8dbcb82 in tf-checks.yml, making this inconsistent as well.

Fix in Cursor Fix in Web

secrets:
GITHUB: ${{ secrets.GITHUB }}
9 changes: 5 additions & 4 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
repos:

- repo: https://github.com/gruntwork-io/pre-commit
rev: v0.1.12 # Get the latest from: https://github.com/gruntwork-io/pre-commit/releases
rev: v0.1.23 # Get the latest from: https://github.com/gruntwork-io/pre-commit/releases
hooks:
- id: terraform-fmt
- id: shellcheck
- id: tflint

- repo: git://github.com/pre-commit/pre-commit-hooks
rev: v4.0.1 # Use the ref you want to point at
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0 # Use the ref you want to point at
hooks:
- id: end-of-file-fixer
- id: trailing-whitespace
Expand All @@ -17,4 +18,4 @@ repos:
- id: check-merge-conflict
- id: debug-statements
- id: check-yaml
- id: check-added-large-files
- id: check-added-large-files
42 changes: 42 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Security Policy

## Supported Versions

We actively maintain the latest major release of each module. Security fixes are applied to the latest release only.

| Version | Supported |
|---------|-----------|
| Latest | Yes |
| Older | No |

## Reporting a Vulnerability

**Please do not report security vulnerabilities through public GitHub issues.**

To report a security issue, email us at **support@clouddrove.com** with the subject line:
`[SECURITY] terraform-do-modules/<repo-name>`

Include as much of the following as possible:

- Type of issue (e.g. exposed secret, privilege escalation, insecure default)
- Affected module and version/git ref
- Steps to reproduce or proof-of-concept
- Potential impact assessment

We will acknowledge receipt within **48 hours** and aim to provide a fix or mitigation within **7 days** for critical issues.

## Scope

This policy covers:
- Terraform module code in this repository
- GitHub Actions workflow configurations
- Example configurations under `_examples/`

This policy does **not** cover:
- The DigitalOcean provider itself (report to [HashiCorp](https://www.hashicorp.com/security) or [DigitalOcean](https://www.digitalocean.com/security))
- Issues in third-party dependencies (report upstream)

## Preferred Languages

We accept reports in **English**.

78 changes: 78 additions & 0 deletions docs/architecture.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Architecture: terraform-digitalocean-vpc

## Overview

A Virtual Private Cloud (VPC) is the network foundation for all DigitalOcean resources. It provides a logically isolated network environment in which droplets, Kubernetes clusters, databases, and load balancers communicate using private IP addresses, without traversing the public internet. This module manages a single `digitalocean_vpc` resource and applies consistent naming via the shared labels module.

## VPC as Network Foundation

Every workload in DigitalOcean that requires private networking must be placed inside a VPC. The VPC is created first and its `id` output is passed as `vpc_uuid` to downstream modules. This dependency chain ensures resources are always colocated on the same private network fabric.

Typical dependency order:

1. VPC (this module)
2. Droplet / Kubernetes / Database modules (consume `vpc.id`)
3. Load Balancer module (attached to the VPC-resident resources)

## CIDR Planning (RFC 1918)

DigitalOcean VPCs accept any CIDR block that satisfies all of the following:

- Falls within RFC 1918 private address space: `10.0.0.0/8`, `172.16.0.0/12`, or `192.168.0.0/16`
- Is no larger than `/16` (65 536 addresses)
- Is no smaller than `/24` (256 addresses)

Recommended sizing guidance:

| Use case | CIDR example | Usable hosts |
|--------------------|-------------------|--------------|
| Small environment | 10.x.x.0/24 | 254 |
| Medium environment | 10.x.0.0/22 | 1 022 |
| Large environment | 10.x.0.0/16 | 65 534 |

Choose non-overlapping ranges across all VPCs in the same account and across any remote networks that may be peered or connected via VPN in the future.

## Regional Scope

A DigitalOcean VPC is scoped to a single region (e.g., `blr1`, `nyc3`, `fra1`, `sgp1`). All resources attached to a VPC must reside in the same region. Cross-region private connectivity is not natively supported; inter-region traffic must traverse the public internet or a private VPN endpoint.

This module exposes the `region` variable (default `blr1`) so that the VPC region matches the region used by downstream modules.

## Integration with Other Modules

| Consumer module | Input variable | Source output |
|----------------------------------|-----------------|-----------------|
| terraform-digitalocean-droplet | `vpc_uuid` | `module.vpc.id` |
| terraform-digitalocean-kubernetes| `vpc_uuid` | `module.vpc.id` |
| terraform-digitalocean-database | `vpc_uuid` | `module.vpc.id` |
| terraform-digitalocean-lb | `vpc_uuid` | `module.vpc.id` |

Example wiring:

```hcl
module "vpc" {
source = "terraform-do-modules/vpc/digitalocean"
version = "1.0.0"
name = "app"
environment = "prod"
region = "blr1"
ip_range = "10.10.0.0/16"
}

module "cluster" {
source = "terraform-do-modules/kubernetes/digitalocean"
version = "1.0.0"
vpc_uuid = module.vpc.id
# ...
}
```

## Operational Checklist

- Do not use overlapping CIDR ranges across VPCs in the same account or with on-premises networks.
- DigitalOcean does not support native VPC peering; plan CIDR ranges as if each VPC is a standalone island.
- Each account has a default VPC per region; avoid using it for workloads — the `default` output identifies whether the VPC is the region default.
- Pin the module version in production to prevent unintended VPC replacement on version upgrades.
- VPC deletion is blocked if resources are still attached; decommission all droplets, clusters, and databases first.
- Set `enabled = false` to skip resource creation without removing the module call from the configuration.
- Record the VPC `id` and `urn` outputs in remote state so they are referenceable by other root modules without hard-coding.
23 changes: 23 additions & 0 deletions docs/io.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Inputs and Outputs: terraform-digitalocean-vpc

## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|----------|
| `name` | Name (e.g. `app` or `cluster`). | `string` | `""` | no |
| `environment` | Environment (e.g. `prod`, `dev`, `staging`). | `string` | `""` | no |
| `label_order` | Label order, e.g. `name`. | `list(any)` | `["name", "environment"]` | no |
| `managedby` | ManagedBy, eg `terraform-do-modules` or `hello@clouddrove.com`. | `string` | `"terraform-do-modules"` | no |
| `enabled` | A boolean flag to enable/disable vpc. | `bool` | `true` | no |
| `region` | The region to create VPC, like `blr1`. | `string` | `"blr1"` | no |
| `description` | A free-form text field up to a limit of 255 characters to describe the VPC. | `string` | `"VPC"` | no |
| `ip_range` | The range of IP addresses for the VPC in CIDR notation. Network ranges cannot overlap with other networks in the same account and must be in range of private addresses as defined in RFC1918. It may not be larger than /16 or smaller than /24. | `string` | `""` | no |

## Outputs

| Name | Description |
|------|-------------|
| `id` | The unique identifier for the VPC. |
| `urn` | The uniform resource name (URN) for the VPC. |
| `default` | A boolean indicating whether or not the VPC is the default one for the region. |
| `created_at` | The date and time of when the VPC was created. |
Loading