File size: 44,396 Bytes
41f63cf 99cf161 41f63cf | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 | <!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>OpenBao Vault Migration check — check vault files for openbao</title>
<meta name="description" content="This browser tool checks HashiCorp Vault files for images, Helm charts, storage backends, seals, and plugins that OpenBao 2.7 does not build in, and shows the OpenBao fix.">
<style>
:root{color-scheme:light}body{margin:0;font:15px/1.55 system-ui,-apple-system,"Segoe UI",sans-serif;background:#faf9f5;color:#1a1512}
.wrap{max-width:960px;margin:0 auto;padding:28px 18px 60px}h1{font-size:26px;margin:0 0 6px}.lede{color:#4a403a;margin:0 0 16px}
textarea{width:100%;min-height:260px;font:13px/1.45 ui-monospace,Menlo,Consolas,monospace;padding:12px;border:1px solid #d9d0c4;border-radius:8px;box-sizing:border-box}
.bar{display:flex;gap:10px;align-items:center;margin:12px 0}button{font:600 15px system-ui;padding:10px 18px;border:0;border-radius:8px;background:#1a1512;color:#fff;cursor:pointer}
input[type=date]{font:14px system-ui;padding:8px;border:1px solid #d9d0c4;border-radius:6px}
table{border-collapse:collapse;width:100%;font-size:14px;margin-top:10px}th,td{text-align:left;padding:8px 10px;border-bottom:1px solid #eee;vertical-align:top}th{font-size:12px;letter-spacing:.06em;text-transform:uppercase;color:#7a6e65}
.sev.error{color:#a8551f;font-weight:700}.sev.warn,.sev.warning{color:#96691f}.ok{color:#2a6446;font-weight:600}.sum{font-weight:600}
.note{font-size:13px;color:#7a6e65;margin-top:18px}#paid{margin-top:22px;padding:14px 16px;border:1px solid #e2d8cb;border-radius:10px;background:#fffdfa}
</style>
<script data-grow-initializer="">!(function(){window.growMe||((window.growMe=function(e){window.growMe._.push(e);}),(window.growMe._=[]));var e=document.createElement("script");(e.type="text/javascript"),(e.src="https://faves.grow.me/main.js"),(e.defer=!0),e.setAttribute("data-grow-faves-site-id","U2l0ZTphZjljMzgyMC0yMmU5LTRhYjgtYTIxNS03OTRhMGY1N2ExYzM=");var t=document.getElementsByTagName("script")[0];t.parentNode.insertBefore(e,t);})();</script>
<!--yj-canon-s101--><link rel="canonical" href="https://getreadystack.com/tools/openbao-migration-lint"></head>
<body>
<div class="wrap">
<h1>OpenBao Vault Migration check — check vault files for openbao</h1>
<p class="lede">OpenBao migration check for HashiCorp Vault files: flags BSL Vault 1.15+ images, Helm charts, storage backends, seals and plugins OpenBao 2.7 does not build in, with the OpenBao fix. Runs entirely in your browser — nothing is uploaded.</p>
<textarea id="src" spellcheck="false">#!/usr/bin/env bash
# deploy-vault.sh - secrets platform bootstrap
set -euo pipefail
export VAULT_ADDR="https://vault.internal:8200"
export VAULT_LICENSE_PATH="/etc/vault.d/vault.hclic"
cat > /etc/vault.d/vault.hcl <<'HCL'
ui = true
disable_mlock = true
license_path = "/etc/vault.d/vault.hclic"
storage "consul" {
address = "127.0.0.1:8500"
path = "vault/"
}
seal "awskms" {
region = "eu-central-1"
kms_key_id = "alias/vault-unseal"
}
listener "tcp" {
address = "0.0.0.0:8200"
}
HCL
docker pull hashicorp/vault:1.17.2
helm repo add hashicorp https://helm.releases.hashicorp.com
helm upgrade --install vault hashicorp/vault -n vault
vault login -method=oidc
vault auth enable aws
vault secrets enable -path=db database
vault write db/config/orders plugin_name=mssql-database-plugin connection_url="sqlserver://{{username}}:{{password}}@sql01:1433"
if [[ "$VAULT_TOKEN" != hvs.* ]]; then echo "bad token" >&2; exit 1; fi</textarea>
<div class="bar"><button id="go">Check</button><label>as of <input type="date" id="today"></label></div>
<div id="out" aria-live="polite"></div>
<div id="paid"><strong>Free here:</strong> Every finding in the open file, with the Vault line that breaks and the OpenBao fix, free and offline. <strong>Full version ($29 once, one licence key per person or team seat):</strong> <a href="https://getreadystack.com/api/buy/cl/polar_cl_lLldqowNNwX8HlbXeAJMYp5W6WZOIdpQp49P92L6C2o">Scan the whole workspace in one pass and export one migration report for the change ticket</a>.</div>
<p class="note">Same engine as the VS Code extension, byte for byte.</p>
</div>
<script>var OB_RULES = [
{
"id": "vault-bsl-image",
"sev": "error",
"kind": "vault_image",
"when": "bsl",
"msg": "HashiCorp Vault image under the Business Source License: the Vault LICENSE covers 'Vault Version 1.15.0 or later' (Licensor: IBM). OpenBao's in-place guide was tested only from Vault 1.14.1 and gives no storage-compatibility guarantee for newer Vault.",
"fix": "Use quay.io/openbao/openbao:\u003c2.x tag\u003e; a Vault 1.15+ data store needs a fresh OpenBao cluster, not an in-place swap."
},
{
"id": "vault-pre-1141-image",
"sev": "warn",
"kind": "vault_image",
"when": "old",
"msg": "Vault older than 1.14.1: OpenBao's in-place migration guide says to upgrade to v1.14.1 first.",
"fix": "Pin hashicorp/vault:1.14.1, upgrade, then swap to quay.io/openbao/openbao."
},
{
"id": "helm-hashicorp-chart",
"sev": "error",
"pats": [
{
"re": "helm\\.releases\\.hashicorp\\.com"
},
{
"re": "\\bhelm\\s+(?:install|upgrade)\\b.*\\shashicorp\\/vault\\b"
},
{
"re": "^\\s*chart:\\s*[\"']?hashicorp\\/vault\\b"
}
],
"msg": "HashiCorp Helm repo or hashicorp/vault chart: it deploys the BSL-licensed Vault server.",
"fix": "helm repo add openbao https://openbao.github.io/openbao-helm then helm install openbao openbao/openbao."
},
{
"id": "hashicorp-package-repo",
"sev": "warn",
"pats": [
{
"re": "\\b(?:apt|rpm)\\.releases\\.hashicorp\\.com\\b"
},
{
"re": "\\b(?:apt|apt-get|yum|dnf)\\s+install\\b.*\\svault\\b"
}
],
"msg": "Installs Vault from HashiCorp's package repository, which ships the current BSL-licensed releases.",
"fix": "Install OpenBao from https://github.com/openbao/openbao/releases (checksums.txt is signed)."
},
{
"id": "storage-not-in-openbao",
"sev": "error",
"pats": [
{
"re": "^\\s*(?:ha_)?storage\\s+\"(consul|s3|dynamodb|etcd|gcs|mysql|zookeeper|azure|cassandra|cockroachdb|couchdb|spanner|swift|manta|oci|foundationdb|file)\""
}
],
"msg": "Storage backend not in OpenBao: the OpenBao 2.7.0 server registers raft, postgresql, pebbledb and inmem only; file storage was removed in 2.7.0 (September 23, 2026).",
"fix": "Move to storage \"raft\" (or postgresql) with bao operator migrate before the swap."
},
{
"id": "seal-plugin-since-2-7",
"sev": "error",
"pats": [
{
"re": "^\\s*seal\\s+\"(awskms|azurekeyvault|gcpckms|alicloudkms|ocikms|pkcs11)\""
}
],
"msg": "Auto-unseal seal that is no longer built in: since OpenBao 2.7.0 (September 23, 2026) the pkcs11, alicloudkms, awskms, azurekeyvault, gcpckms and ocikms seals must be installed as external plugins.",
"fix": "Install the matching seal plugin from github.com/openbao/openbao-plugins before starting 2.7.0."
},
{
"id": "auth-not-builtin",
"sev": "error",
"pats": [
{
"re": "\\bauth\\s+enable\\s+(?:-\\S+\\s+)*(aws|azure|gcp|github|okta|ldap|radius|kerberos|alicloud|cf|oci)\\b"
},
{
"re": "^\\s*type\\s*=\\s*\"(aws|azure|gcp|github|okta|ldap|radius|kerberos|alicloud|cf|oci)\"",
"near": "resource\\s+\"vault_auth_backend\"",
"within": 6
}
],
"msg": "Auth method OpenBao does not ship built in: the OpenBao registry lists approle, cert, jwt, kubernetes, oidc and userpass; kerberos, ldap and radius left the binary in 2.7.0. The mount is skipped at startup and serves no paths.",
"fix": "Install the plugin from openbao-plugins, or move logins to jwt/oidc, kubernetes or cert."
},
{
"id": "secrets-not-builtin",
"sev": "error",
"pats": [
{
"re": "\\bsecrets\\s+enable\\s+(?:-\\S+\\s+)*(aws|azure|gcp|gcpkms|consul|nomad|terraform|ldap|ad|openldap|mongodbatlas|alicloud|kmip|transform|keymgmt)\\b"
},
{
"re": "^\\s*type\\s*=\\s*\"(aws|azure|gcp|gcpkms|consul|nomad|terraform|ldap|ad|openldap|mongodbatlas|alicloud|kmip|transform|keymgmt)\"",
"near": "resource\\s+\"vault_mount\"",
"within": 6
}
],
"msg": "Secrets engine OpenBao does not ship built in (the registry lists kubernetes, kv, pki, rabbitmq, ssh, totp and transit). OpenBao's guide: the mount is skipped at startup and reads return 'No value found'.",
"fix": "Install the plugin from openbao-plugins or re-home these secrets before the swap."
},
{
"id": "db-plugin-not-builtin",
"sev": "error",
"pats": [
{
"re": "\\b(mssql|oracle|mongodb|mongodbatlas|elasticsearch|hana|snowflake|redshift|couchbase)-database-plugin\\b"
}
],
"msg": "Database plugin not built into OpenBao: the built-in list is mysql (4 variants), cassandra, influxdb, postgresql, redis and valkey.",
"fix": "Register an external plugin for this database, or issue these credentials another way."
},
{
"id": "vault-env-prefix",
"sev": "warn",
"pats": [
{
"re": "\\bVAULT_(ADDR|TOKEN|NAMESPACE|CACERT|CAPATH|CLIENT_CERT|CLIENT_KEY|SKIP_VERIFY|AGENT_ADDR)\\b"
}
],
"msg": "VAULT_* variable: the bao CLI and OpenBao's api/client.go read BAO_ADDR, BAO_TOKEN, BAO_NAMESPACE and the other BAO_* names.",
"fix": "Rename to the BAO_ equivalent (VAULT_ADDR becomes BAO_ADDR)."
},
{
"id": "vault-cli-binary",
"sev": "warn",
"pats": [
{
"re": "(?:^|[\\s;\u0026|(`])vault\\s+(login|kv|read|write|list|delete|secrets|auth|operator|token|policy|server|agent|proxy|status|lease|audit|plugin|namespace)\\b"
}
],
"msg": "Calls the vault binary: OpenBao's command is bao (bao operator migrate, bao plugin prune, bao namespace ...).",
"fix": "Replace vault with bao on this line."
},
{
"id": "token-prefix-hvs",
"sev": "warn",
"pats": [
{
"re": "\\bhv[sbr]\\\\?\\."
}
],
"msg": "Checks for Vault's hvs./hvb./hvr. token prefix: OpenBao issues new tokens as s./b./r.\u003crandom\u003e, so this check rejects every token issued after the swap.",
"fix": "Accept both forms, e.g. ^(hv)?[sbr]\\. , or stop parsing the token format."
},
{
"id": "disable-mlock",
"sev": "info",
"pats": [
{
"re": "^\\s*disable_mlock\\s*="
}
],
"msg": "disable_mlock: OpenBao does not use mlock since 2.0.0 and its migration guide says to remove this line.",
"fix": "Delete the disable_mlock line from the server config."
},
{
"id": "enterprise-licence",
"sev": "warn",
"pats": [
{
"re": "^\\s*license_path\\s*="
},
{
"re": "\\bVAULT_LICENSE(?:_PATH)?\\b"
}
],
"msg": "Vault Enterprise licence setting: OpenBao's migration guide covers Vault Community Edition only, not Vault Enterprise.",
"fix": "List the Enterprise features this cluster uses (namespaces, replication, HSM) and test each on OpenBao before cutover."
}
];</script>
<script>/* OpenBao migration lint: one engine for VS Code and the free web page. */
(function () {
var RULES = (typeof module !== 'undefined') ? require('./rules.json') : window.OB_RULES;
var IMG = /\bhashicorp\/vault(-enterprise)?(?![\w-])(?::([0-9A-Za-z._+-]+))?/;
var SKIP_IMG = /^\s*source\s*=|\bhelm\b|^\s*chart:/;
function compile(r) {
return (r.pats || []).map(function (p) {
return { re: new RegExp(p.re), near: p.near ? new RegExp(p.near) : null, within: p.within || 5 };
});
}
var COMPILED = RULES.map(function (r) { return { rule: r, pats: compile(r) }; });
// bsl = Vault 1.15.0+ / latest / enterprise · old = before 1.14.1 · null = 1.14.1-1.14.x
function imageVerdict(line) {
if (SKIP_IMG.test(line)) return null;
var m = IMG.exec(line);
if (!m) return null;
if (m[1]) return 'bsl';
var tag = m[2] || 'latest';
var v = /^v?(\d+)\.(\d+)(?:\.(\d+))?/.exec(tag);
if (!v) return 'bsl';
var maj = +v[1], min = +v[2], pat = v[3] ? +v[3] : 0;
if (maj > 1 || min >= 15) return 'bsl';
if (min < 14 || (min === 14 && pat < 1)) return 'old';
return null;
}
function check(text, opts) {
var lines = String(text || '').split(/\r?\n/);
var findings = [];
for (var i = 0; i < lines.length; i++) {
var line = lines[i];
var img = imageVerdict(line);
for (var k = 0; k < COMPILED.length; k++) {
var r = COMPILED[k].rule, hit = false;
if (r.kind === 'vault_image') {
hit = img === r.when;
} else {
for (var p = 0; p < COMPILED[k].pats.length && !hit; p++) {
var pat = COMPILED[k].pats[p];
if (!pat.re.test(line)) continue;
if (!pat.near) { hit = true; break; }
for (var b = i - 1; b >= 0 && b >= i - pat.within; b--) {
if (pat.near.test(lines[b])) { hit = true; break; }
}
}
}
if (hit) findings.push({ check: r.id, sev: r.sev, msg: r.msg + ' Fix: ' + r.fix, line: i + 1 });
}
}
return { findings: findings };
}
var api = { engine: { check: check }, RULES: RULES, RULE_COUNT: RULES.length };
if (typeof module !== 'undefined') module.exports = api;
if (typeof window !== 'undefined') window.OBENGINE = api;
})();
</script>
<script>// ⛔뼈대 — kit/scaffold.py 가 찍는다 (s143). findings [{check,sev,msg,line?}] → 글/HTML. 같은 파일이 Node 와 브라우저에서 산다.
'use strict';
function escapeHtml(s) { return String(s == null ? '' : s).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"'); }
function summaryLine(res) {
const f = (res && res.findings) || []; const e = f.filter(function (x) { return String(x.sev || 'error').toLowerCase().startsWith('err'); }).length;
return f.length ? (f.length + ' finding' + (f.length === 1 ? '' : 's') + ' (' + e + ' error' + (e === 1 ? '' : 's') + ')') : 'Clean — no findings.';
}
function toText(res, label) {
const f = (res && res.findings) || [];
const lines = ['== ' + (label || '') + ' — ' + summaryLine(res)];
f.forEach(function (x) { lines.push(' ' + String(x.sev || 'error').toUpperCase().slice(0, 4) + ' ' + (x.line ? 'L' + x.line + ' ' : '') + (x.check || x.id || '') + ' ' + (x.msg || x.message || '')); });
return lines.join('\n');
}
function toHtml(res) {
const f = (res && res.findings) || [];
if (!f.length) return '<p class="ok">' + escapeHtml(summaryLine(res)) + '</p>';
const rows = f.map(function (x) { return '<tr><td class="sev ' + escapeHtml(String(x.sev || 'error')) + '">' + escapeHtml(String(x.sev || 'error')) + '</td><td>' + (x.line ? 'L' + escapeHtml(x.line) : '') + '</td><td><code>' + escapeHtml(x.check || x.id || '') + '</code></td><td>' + escapeHtml(x.msg || x.message || '') + '</td></tr>'; }).join('');
return '<p class="sum">' + escapeHtml(summaryLine(res)) + '</p><table><thead><tr><th>Level</th><th>Line</th><th>Check</th><th>What</th></tr></thead><tbody>' + rows + '</tbody></table>';
}
var OBREPORT = { escapeHtml: escapeHtml, summaryLine: summaryLine, toText: toText, toHtml: toHtml };
if (typeof module !== 'undefined' && module.exports) module.exports = OBREPORT;
else window.OBREPORT = OBREPORT;
</script>
<script>
(function(){
var src=document.getElementById('src'), out=document.getElementById('out'), go=document.getElementById('go'), today=document.getElementById('today');
today.value=new Date().toISOString().slice(0,10);
function run(){ try { var res=window.OBENGINE.engine.check(src.value,{today:today.value}); out.innerHTML=window.OBREPORT.toHtml(res); } catch(e){ out.innerHTML='<p class="sev error">Could not run: '+String(e.message||e)+'</p>'; } }
go.onclick=run; if (src.value.trim()) run();
})();
</script>
<section data-yj-install="free" style="margin:2rem auto 1rem;max-width:46rem;padding:1.25rem 1.25rem;border:1px solid #cfe3d6;border-radius:12px;background:#f6fbf8;font:16px/1.6 system-ui,-apple-system,Segoe UI,sans-serif"><h2 style="margin:0 0 .4rem;font-size:1.2rem">Install free</h2><p style="margin:0 0 .8rem;color:#41505f">Free for the file open in your editor - no key, no limit. The workspace sweep and the report ask for a key.</p><a href="https://open-vsx.org/extension/readystack/openbao-migration-lint" rel="noopener" data-yj-install-door="ovsx" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'openbao-migration-lint',src:'ovsx',path:location.pathname})],{type:'application/json'}))}catch(e){}" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">Open VSX (Cursor, VSCodium)</a><a href="https://www.npmjs.com/package/@readystack/openbao-migration-lint" rel="noopener" data-yj-install-door="npm" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'openbao-migration-lint',src:'npm',path:location.pathname})],{type:'application/json'}))}catch(e){}" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">npm</a><a href="https://hub.docker.com/r/getreadystack/openbao-migration-lint" rel="noopener" data-yj-install-door="docker" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'openbao-migration-lint',src:'docker',path:location.pathname})],{type:'application/json'}))}catch(e){}" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">Docker Hub</a><pre style="margin:.5rem 0 0;padding:.6rem .8rem;background:#f3f5f8;border-radius:8px;font-size:.9rem;overflow:auto">npx @readystack/openbao-migration-lint <file>
docker run --rm -v "$PWD:/w" getreadystack/openbao-migration-lint /w</pre><p style="margin:.6rem 0 0;font-size:.92rem;color:#41505f"><a href="https://getreadystack.com/api/buy/cl/polar_cl_l6iN1uWt0FwWu7tBsczD0jWpP2vxFM54Wdwqb3KPi1G" rel="nofollow" style="color:#0f7b3f;text-decoration:underline">Team? One key for every ReadyStack linter, 5 seats, $149 once</a></p></section>
<section data-yj-alert="rule" style="margin:1rem auto 1.5rem;max-width:46rem;padding:1.1rem 1.25rem;border:1px solid #d9dee6;border-radius:12px;background:#fbfcfd;font:15px/1.55 system-ui,-apple-system,Segoe UI,sans-serif"><b style="font-size:1.05rem">Get the full rule table as a PDF</b><div style="opacity:.78;margin:.35rem 0 .8rem">All 14 rules OpenBao Migration Lint — HashiCorp Vault checks, each with its source and date, on printable pages you can hand to your team or auditor. We email it now, and once more only if a rule changes. No newsletter.</div><div style="display:flex;gap:8px;flex-wrap:wrap"><input id="yjae" type="email" placeholder="you@example.com" style="flex:1;min-width:210px;padding:11px 13px;border:1px solid rgba(140,150,165,.34);border-radius:8px;background:#fff;color:inherit"><button id="yjab" style="padding:11px 18px;border-radius:8px;border:0;cursor:pointer;background:#0f7b3f;color:#fff;font:600 15px system-ui,sans-serif">Email me the PDF</button></div><div id="yjao" hidden style="margin-top:.6rem;color:#0f7b3f">Sent. It arrives within the hour - check spam too.</div><script>(function(){var b=document.getElementById("yjab"),e=document.getElementById("yjae");if(!b||!e)return;b.addEventListener("click",function(){var v=e.value.trim();if(!/.+@.+\..+/.test(v))return;try{localStorage.setItem("yj_em","1");}catch(_){}fetch(location.origin+"/api/subscribe",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({email:v,slug:"openbao-migration-lint",lang:"en",source:"rule_table"+((b.closest&&b.closest("section")&&b.closest("section").getAttribute("data-yj-moved"))?"_at_result":"")})}).then(function(r){var o=document.getElementById("yjao");o.hidden=false;if(!r.ok){o.textContent="Could not save - please try again.";}}).catch(function(){var o=document.getElementById("yjao");o.hidden=false;o.textContent="Could not save - please try again.";});});})();</script><script>(function(){var e=document.getElementById("yjae"),s=e&&e.closest?e.closest("section"):null,o=document.getElementById("out");if(!s||!o)return;var d=false;function mv(ev){if(d)return;if(ev&&ev.target&&s.contains(ev.target))return;d=true;var b=o;while(b.parentNode&&b.parentNode!==document.body&&b.parentNode.tagName!=="MAIN"&&b.parentNode.tagName!=="ARTICLE")b=b.parentNode;if(!b.parentNode||b===s||b.contains(s))return;try{b.parentNode.insertBefore(s,b.nextSibling);s.setAttribute("data-yj-moved","1");}catch(_){}}document.addEventListener("input",mv,true);document.addEventListener("change",mv,true);})();</script></section>
<section data-yj-cta="paid" style="margin:3rem auto;max-width:46rem;padding:1.5rem 1.25rem;border:1px solid #d8dee9;border-radius:12px;background:#fbfcfe;font:16px/1.6 system-ui,-apple-system,Segoe UI,sans-serif"><h2 style="margin:0 0 .5rem;font-size:1.25rem">Get the complete version <span class="yj-price">$29</span></h2><p style="margin:.25rem 0 1rem;color:#41505f">This page is the working piece. The full pack has everything below.</p><p style="margin:0 0 1rem;color:#41505f">OpenBao migration check for HashiCorp Vault scripts, Terraform, Helm values and server HCL: 14 rules, each with the OpenBao fix</p><p style="margin:0 0 1rem;color:#5b6b7c;font-size:.94rem">DOJ's Fitzpatrick Matrix rates a 15-year litigator at $851/hour for billing year 2026, which is one hour of counsel reading the BSL Additional Use Grant.</p><a href="https://getreadystack.com/api/buy/cl/polar_cl_lLldqowNNwX8HlbXeAJMYp5W6WZOIdpQp49P92L6C2o" rel="nofollow" style="display:inline-block;padding:.7rem 1.3rem;border-radius:8px;background:#1b64f2;color:#fff;text-decoration:none;font-weight:600">Buy the full version — $29</a></section>
<!--yj-share-s101--><div style="margin:28px 0 8px;text-align:center"><button id="yjcp" type="button" style="font:inherit;padding:10px 18px;border:1px solid #8884;border-radius:10px;background:transparent;cursor:pointer">Copy link</button><button id="yjimg" type="button" style="font:inherit;padding:10px 18px;margin-left:8px;border:1px solid #8884;border-radius:10px;background:transparent;cursor:pointer">Save result as image</button></div><script>(function(){var b=document.getElementById("yjimg");if(!b)return;b.addEventListener("click",function(){var o=document.getElementById("out");var txt=(o&&(o.innerText||o.textContent)||"").trim();if(!txt){b.textContent="(no result yet)";setTimeout(function(){b.textContent="Save result as image";},1500);return;}var lines=txt.split(String.fromCharCode(10)).filter(function(x){return x.trim();}).slice(0,10);var W=1200,P=56,c=document.createElement("canvas");c.width=W;var lh=38,H=P*2+70+lines.length*lh+60;c.height=H;var x=c.getContext("2d");x.fillStyle="#1a1512";x.fillRect(0,0,W,H);x.fillStyle="#f3e9d2";x.font="600 34px system-ui,Segoe UI,Arial";var t=(document.title||"").split("|")[0].trim();x.fillText(t.slice(0,54),P,P+34);x.font="22px ui-monospace,Menlo,Consolas,monospace";x.fillStyle="#e8dcc4";for(var i=0;i<lines.length;i++){x.fillText(lines[i].slice(0,88),P,P+70+i*lh+22);}x.font="600 22px system-ui,Segoe UI,Arial";x.fillStyle="#c9a227";var d=location.hostname.replace("www.","");x.fillText(d,W-P-x.measureText(d).width,H-P+6);c.toBlob(function(bl){var u=URL.createObjectURL(bl),a=document.createElement("a");a.href=u;a.download=(t||"result").replace(/[^a-z0-9]+/gi,"-").toLowerCase()+"-"+d+".png";document.body.appendChild(a);a.click();setTimeout(function(){URL.revokeObjectURL(u);a.remove();},2000);},"image/png");});})();</script><script>(function(){var b=document.getElementById("yjcp");if(!b)return;var t=b.textContent;b.addEventListener("click",function(){var u=location.href.split("#")[0];function d(){b.textContent="Link copied";setTimeout(function(){b.textContent=t;},1800);}if(navigator.clipboard&&navigator.clipboard.writeText){navigator.clipboard.writeText(u).then(d,function(){prompt("",u);});}else{prompt("",u);}});})();</script>
<script data-yj="yj-view-beacon">(function(){try{var p=location.pathname;var k='yjv:'+p;if(sessionStorage.getItem(k))return;sessionStorage.setItem(k,'1');fetch('/api/ev',{method:'POST',keepalive:true,headers:{'Content-Type':'application/json'},body:JSON.stringify({path:p,lang:"en",ref:(document.referrer||''),src:(function(){try{return (new URLSearchParams(location.search).get('ref')||'').replace(/[^a-z_]/g,'').slice(0,12)}catch(e){return ''}})()})}).catch(function(){});}catch(e){}})();</script>
<script data-yj="yj-use-beacon">(function(){try{var o=document.getElementById('out');if(!o)return;var p=location.pathname,k='yju:'+p,sent=false;function fire(){if(sent||sessionStorage.getItem(k))return;if(!(o.textContent||'').replace(/\s+/g,'').length)return;sent=true;sessionStorage.setItem(k,'1');fetch('/api/ev',{method:'POST',keepalive:true,headers:{'Content-Type':'application/json'},body:JSON.stringify({path:p,lang:"en",t:'use',src:(function(){try{return (new URLSearchParams(location.search).get('ref')||'').replace(/[^a-z_]/g,'').slice(0,12)}catch(e){return ''}})()})}).catch(function(){});}var mo=new MutationObserver(function(){fire();if(sent)mo.disconnect();});mo.observe(o,{childList:true,characterData:true,subtree:true});}catch(e){}})();</script><div class="yj-home-find"><div class="yj-lgbar"><a href="/" class="yj-lg on">EN</a><a href="/de/" class="yj-lg">DE</a><a href="/ja/" class="yj-lg">JA</a><a href="/es/" class="yj-lg">ES</a><a href="/pt/" class="yj-lg">PT</a></div><section class="yj-find"><h2>Find a tool</h2><input id="yjq" type="search" autocomplete="off" placeholder="Type a product name, format or task"><div id="yjr"></div></section><style>.yj-lgbar{position:absolute;top:14px;right:18px;display:flex;gap:6px;z-index:60}.yj-lg{font:600 12px/1 system-ui,sans-serif;padding:6px 9px;border-radius:4px;text-decoration:none;color:#8b96a3;border:1px solid rgba(140,150,165,.28)}.yj-lg:hover{color:#e8eaed;border-color:rgba(160,175,195,.6)}.yj-lg.on{color:#0e1116;background:#cfd6de;border-color:#cfd6de}.yj-find{max-width:760px;margin:34px auto 8px;padding:0 20px}.yj-find h2{font:600 20px/1.3 system-ui,sans-serif;margin:0 0 10px}#yjq{width:100%;box-sizing:border-box;padding:13px 15px;font:400 15.5px system-ui,sans-serif;border:1px solid rgba(140,150,165,.34);border-radius:8px;background:rgba(255,255,255,.04);color:inherit}#yjq:focus{outline:none;border-color:#7FD1C4}#yjr{margin-top:10px;display:flex;flex-direction:column;gap:6px}#yjr a{display:flex;justify-content:space-between;gap:12px;padding:11px 14px;border:1px solid rgba(140,150,165,.22);border-radius:6px;text-decoration:none;font:400 14.5px/1.4 system-ui,sans-serif;color:inherit}#yjr a:hover{border-color:#7FD1C4}#yjr .pr{font:600 13px system-ui,sans-serif;color:#5fbf9a;white-space:nowrap}</style><script>(function(){var q=document.getElementById("yjq"),r=document.getElementById("yjr"),D=null;function load(){if(D)return Promise.resolve(D);return fetch("/search-index.json").then(function(x){return x.json();}).then(function(j){D=j;return j;}).catch(function(){D=[];return D;});}function esc(t){return String(t).replace(/[&<>"]/g,function(c){return {"&":"&","<":"<",">":">",'"':"""}[c];});}function run(){var v=q.value.trim().toLowerCase();if(v.length<2){r.innerHTML="";return;}load().then(function(j){var w=v.split(/\s+/),o=[];for(var i=0;i<j.length&&o.length<12;i++){var t=j[i].t.toLowerCase();var ok=true;for(var k=0;k<w.length;k++){if(t.indexOf(w[k])<0){ok=false;break;}}if(ok)o.push(j[i]);}r.innerHTML=o.length?o.map(function(x){return "<a href=\""+esc(x.u)+"\">"+"<span>"+esc(x.t)+"</span>"+(x.p?"<span class=\"pr\">$"+x.p+"</span>":"")+"</a>";}).join(""):"";});}q.addEventListener("input",run);q.addEventListener("focus",load);})();</script></div><section data-yj="yj-facts-v1" style="max-width:920px;margin:48px auto 0;padding:0 20px;font-family:system-ui,sans-serif"><style>.yj-article p{font:400 15.5px/1.7 system-ui,sans-serif;color:#26313b;margin:0 0 12px;max-width:72ch}.yj-article h2,.yj-article h3,.yj-article h4{font:600 17px/1.35 system-ui,sans-serif;color:#1b1f24;margin:22px 0 8px}.yj-article table{border-collapse:collapse;margin:10px 0 16px;font:14px/1.45 system-ui,sans-serif}.yj-article th,.yj-article td{border:1px solid #e2e6ea;padding:6px 10px;text-align:left}.yj-article th{background:#f4f6f8}.yj-article pre{background:#0f1720;color:#e6edf3;padding:12px 14px;border-radius:8px;overflow:auto;font:13px/1.5 ui-monospace,Menlo,monospace}.yj-article code{font:13px ui-monospace,Menlo,monospace;background:#f1f3f5;padding:1px 4px;border-radius:3px}.yj-article pre code{background:none;padding:0}.yj-article ul,.yj-article ol{font:15px/1.6 system-ui,sans-serif;color:#26313b}</style><p style="font:400 13px/1.5 system-ui,sans-serif;color:#6b7680;margin:0 0 14px"><time datetime="2026-09-28">Updated 2026-09-28</time> · ReadyStack</p><script type="application/ld+json">{"@context":"https://schema.org","@type":"WebPage","dateModified":"2026-09-28","author":{"@type":"Organization","name":"ReadyStack"}}</script><h2 style="font:600 21px/1.3 system-ui,sans-serif;margin:0 0 6px;color:#1b1f24">Worked example</h2><p style="font:400 14.5px/1.5 system-ui,sans-serif;margin:0 0 16px;color:#5b6570">Real numbers from this tool, line by line.</p><div class="yj-article"><p><img src="https://getreadystack.com/img/promo/sku353992_result_card.jpg" alt="OpenBao Migration Lint — HashiCorp Vault" loading="lazy" style="max-width:100%;border-radius:6px"></p>
<p>17 findings in a 31-line HashiCorp Vault deploy script: that is what a line-by-line OpenBao migration check reports for the platform, SRE and DevOps engineers who own self-managed Vault and now have to move it to OpenBao.</p>
<h3>Migrate from HashiCorp Vault to OpenBao: what changed and when</h3>
<p>The Vault LICENSE file names "Vault Version 1.15.0 or later" as the Licensed Work under the Business Source License, with IBM as licensor. Vault 1.14.x was the last line before that, and OpenBao, the fork, publishes an in-place migration guide tested from Vault 1.14.1 only. Then, on September 23, 2026, OpenBao 2.7.0 shipped and moved more pieces out of the binary: the pkcs11, alicloudkms, awskms, azurekeyvault, gcpckms and ocikms seals became external plugins, the Kerberos, LDAP and RADIUS auth methods and the LDAP secrets engine left the main distribution, and the file storage backend was removed.</p>
<p>So a migration plan written in the spring is already out of date. The config that unsealed with awskms on OpenBao 2.6 needs a plugin installed before it starts on 2.7.0.</p>
<h3>The sample script</h3>
<p>Our sample is a normal bootstrap script: it exports VAULT_ADDR, writes a server config through a heredoc, pulls hashicorp/vault:1.17.2, installs the HashiCorp Helm chart, logs in, enables aws auth, configures an mssql database connection and rejects any token that does not start with hvs.</p>
<p>Run through the 14 rules, it gives 7 errors, 9 warnings and 1 info:</p>
<ul><li>seal "awskms": no longer built in since 2.7.0. Fix: install the awskms seal plugin from openbao-plugins.</li><li>storage "consul": the OpenBao 2.7.0 server registers raft, postgresql, pebbledb and inmem only. Fix: move to raft with bao operator migrate.</li><li>hashicorp/vault:1.17.2: BSL, and newer than the 1.14.1 the guide was tested from. Fix: quay.io/openbao/openbao on a fresh cluster.</li><li>vault auth enable aws: the OpenBao plugin registry builds in approle, cert, jwt, kubernetes, oidc and userpass. The guide says a mount without its plugin is skipped at startup and serves no paths.</li><li>plugin_name=mssql-database-plugin: built-in database plugins are mysql, cassandra, influxdb, postgresql, redis and valkey.</li><li>the hvs. check: OpenBao issues new tokens as s.<random>, so the script would reject every token issued after the swap.</li></ul>
<p>The warnings are the quiet ones: VAULT_ADDR and VAULT_TOKEN (OpenBao's api/client.go reads BAO_ADDR and BAO_TOKEN), four calls to the vault binary (the command is bao) and two Enterprise licence settings. The info is disable_mlock, which OpenBao has not used since 2.0.0.</p>
<h3>Why grep and chatbots miss it</h3>
<p>A grep for vault matches every path, comment and bucket name, and says nothing about which seal names are now plugins. A chatbot trained before September 23, 2026 still describes awskms as built in. The facts sit in three places that change every release: the CHANGELOG, internal/helper/builtinplugins/registry.go and internal/command/commands.go. The linter carries those lists and shows the exact line.</p>
<h3>Try it on your own files</h3>
<p>Open the free web version, paste a script, Terraform module, Helm values file or server HCL and press Check. The same engine runs in the VS Code extension on the open file, with every finding free. The OpenBao version of the sample script gives 0 findings, so a clean result means clean. The full version scans a whole workspace and writes one migration report for the change ticket.</p></div><h2 style="font:600 19px/1.3 system-ui,sans-serif;margin:30px 0 10px;color:#1b1f24">15 seconds — what it actually does</h2><video controls muted playsinline preload="none" poster="/img/promo/sku353992_result_card.jpg" style="width:100%;max-width:360px;border-radius:10px;display:block;margin:0 auto"><source src="/media/sku353992_short.mp4" type="video/mp4"></video><h2 style="font:600 21px/1.3 system-ui,sans-serif;margin:34px 0 6px;color:#1b1f24">Questions people ask</h2><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What does OpenBao Migration Lint check in my HashiCorp Vault files?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">It reads shell scripts, Terraform, Helm values, Dockerfiles and Vault server HCL line by line against 14 rules and marks every line that breaks or changes on OpenBao: hashicorp/vault images at 1.15.0 or later (BSL), HashiCorp Helm charts, consul or s3 storage, awskms or pkcs11 seals, auth and secrets plugins OpenBao does not build in, VAULT_* variables, the vault binary and hvs. token checks. Each finding names the OpenBao fix.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">Who is OpenBao Migration Lint for?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">Platform, SRE and DevOps engineers who run self-managed HashiCorp Vault Community Edition and must move to OpenBao because Vault 1.15.0 and later ship under the Business Source License. It suits the person who owns the deploy scripts, Terraform modules and Helm values and has to say, before the change window, which lines will stop working after the swap.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">Why not ask a chatbot or grep for the word vault?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">A plain grep for vault hits every comment and path and misses the real breakers: a seal "awskms" stanza that OpenBao 2.7.0 (September 23, 2026) no longer builds in, a storage "consul" block OpenBao never registered, or a script that rejects any token not starting with hvs. Chatbots trained before 2.7.0 still describe those seals as built in.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What is free and what does the $29 version add?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">Free: every finding in the open file, in VS Code or on the web page, with the Vault line that breaks and the OpenBao fix, offline and without an account. The $29 full version, paid once, scans the whole workspace in one pass and writes one migration report for the change ticket, listing each file, line, rule and fix.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What does the alternative cost?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">Reading the Vault LICENSE, the OpenBao 2.7.0 changelog and the plugin registry by hand takes an engineer most of a day per repository. If the question becomes legal, DOJ's Fitzpatrick Matrix rates a 15-year litigator at $851/hour for billing year 2026. The free tier answers the technical half for each file at no cost.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">Why not just ask ChatGPT or another AI chat?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">A general AI chat answers from training data with a cutoff date, cannot read your repository and names no rule version. OpenBao Migration Lint — HashiCorp Vault checks the file you open against 14 rules from a rule set dated 2026-09-28, and points at the exact line with the fix. For a filing, an audit or a client you need that dated result on your own files.</p></details><script type="application/ld+json" data-yj="yj-faq-ld">{"@context": "https://schema.org", "@type": "FAQPage", "mainEntity": [{"@type": "Question", "name": "What does OpenBao Migration Lint check in my HashiCorp Vault files?", "acceptedAnswer": {"@type": "Answer", "text": "It reads shell scripts, Terraform, Helm values, Dockerfiles and Vault server HCL line by line against 14 rules and marks every line that breaks or changes on OpenBao: hashicorp/vault images at 1.15.0 or later (BSL), HashiCorp Helm charts, consul or s3 storage, awskms or pkcs11 seals, auth and secrets plugins OpenBao does not build in, VAULT_* variables, the vault binary and hvs. token checks. Each finding names the OpenBao fix."}}, {"@type": "Question", "name": "Who is OpenBao Migration Lint for?", "acceptedAnswer": {"@type": "Answer", "text": "Platform, SRE and DevOps engineers who run self-managed HashiCorp Vault Community Edition and must move to OpenBao because Vault 1.15.0 and later ship under the Business Source License. It suits the person who owns the deploy scripts, Terraform modules and Helm values and has to say, before the change window, which lines will stop working after the swap."}}, {"@type": "Question", "name": "Why not ask a chatbot or grep for the word vault?", "acceptedAnswer": {"@type": "Answer", "text": "A plain grep for vault hits every comment and path and misses the real breakers: a seal \"awskms\" stanza that OpenBao 2.7.0 (September 23, 2026) no longer builds in, a storage \"consul\" block OpenBao never registered, or a script that rejects any token not starting with hvs. Chatbots trained before 2.7.0 still describe those seals as built in."}}, {"@type": "Question", "name": "What is free and what does the $29 version add?", "acceptedAnswer": {"@type": "Answer", "text": "Free: every finding in the open file, in VS Code or on the web page, with the Vault line that breaks and the OpenBao fix, offline and without an account. The $29 full version, paid once, scans the whole workspace in one pass and writes one migration report for the change ticket, listing each file, line, rule and fix."}}, {"@type": "Question", "name": "What does the alternative cost?", "acceptedAnswer": {"@type": "Answer", "text": "Reading the Vault LICENSE, the OpenBao 2.7.0 changelog and the plugin registry by hand takes an engineer most of a day per repository. If the question becomes legal, DOJ's Fitzpatrick Matrix rates a 15-year litigator at $851/hour for billing year 2026. The free tier answers the technical half for each file at no cost."}}, {"@type": "Question", "name": "Why not just ask ChatGPT or another AI chat?", "acceptedAnswer": {"@type": "Answer", "text": "A general AI chat answers from training data with a cutoff date, cannot read your repository and names no rule version. OpenBao Migration Lint — HashiCorp Vault checks the file you open against 14 rules from a rule set dated 2026-09-28, and points at the exact line with the fix. For a filing, an audit or a client you need that dated result on your own files."}}]}</script><div id="yj-ask" style="margin:36px 0 0;padding:18px 18px 16px;border:1px solid #e2e6ea;border-radius:10px;background:#fbfbfc"><h2 style="font:600 19px/1.3 system-ui,sans-serif;margin:0 0 4px;color:#1b1f24">Ask about this tool</h2><p style="font:400 13.5px/1.5 system-ui,sans-serif;margin:0 0 12px;color:#5b6570">One question, answered by the person who built it. Your email only if you want the answer sent.</p><form onsubmit="return yjAsk(event)" style="display:grid;gap:8px"><textarea name="question" required minlength="10" maxlength="2000" rows="3" placeholder="Your question" style="font:14px/1.5 system-ui,sans-serif;padding:10px;border:1px solid #cfd6dd;border-radius:6px"></textarea><div style="display:flex;gap:8px;flex-wrap:wrap"><input type="email" name="email" placeholder="Email (optional)" style="flex:1;min-width:200px;font:14px system-ui,sans-serif;padding:9px 10px;border:1px solid #cfd6dd;border-radius:6px"><button type="submit" style="font:600 14px system-ui,sans-serif;padding:9px 18px;border:0;border-radius:6px;background:#1b1f24;color:#fff;cursor:pointer">Send</button></div><p id="yj-ask-msg" style="font:13px system-ui,sans-serif;margin:2px 0 0;color:#0a6238;min-height:1em"></p></form><script>function yjAsk(e){e.preventDefault();var f=e.target,m=document.getElementById("yj-ask-msg");m.style.color="#0a6238";fetch(location.origin+"/api/ask",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({sku:353992,slug:"openbao-migration-lint",lang:"en",question:f.question.value,email:f.email.value,page:location.pathname})}).then(function(r){if(!r.ok)throw 0;m.textContent="Thanks \u2014 noted. Answers land on this page and, if you left an email, in your inbox.";f.question.value="";}).catch(function(){m.style.color="#a8551f";m.textContent="Could not send. Please try again in a minute.";});return false;}</script></div></section><section class="yj-related" style="max-width:920px;margin:56px auto 40px;padding:0 20px"><h2 style="font:600 21px/1.3 system-ui,sans-serif;margin:0 0 6px;color:#1b1f24">Same job, next tool</h2><p style="font:400 14.5px/1.5 system-ui,sans-serif;margin:0 0 20px;color:#5b6570">Free in the browser. The full version is a one-time licence.</p><div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:14px"><a class="yj-rel-c" href="https://getreadystack.com/tools/mcp-2026-migration-lint"><span class="yj-rel-t">MCP 2026 Migration Lint</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/robots-txt-ai-crawler-audit"><span class="yj-rel-t">AI Crawler Rules - robots.txt Audit for AI Search</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/aks-eks-support-cliff-lint"><span class="yj-rel-t">AKS LTS & EKS Extended Support Lint for Terraform</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/bitnami-image-catalog-gate"><span class="yj-rel-t">Bitnami Image Gate: Compose, Helm, Dockerfile</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/bulk-sender-lint"><span class="yj-rel-t">Bulk Sender Lint - the Gmail, Yahoo and Outlook.com rules, checked in your mai</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/cloud-cost-landmine-lint"><span class="yj-rel-t">Cloud Cost Landmine Lint for Terraform, CloudFormation and Kubernetes</span><span class="yj-rel-p">$29</span></a></div><style>.yj-rel-c{display:flex;flex-direction:column;gap:8px;padding:15px 16px;border:1px solid #e2e6ea;border-radius:6px;text-decoration:none;background:#fff}.yj-rel-c:hover{border-color:#b9c2cb;background:#fafbfc}.yj-rel-t{font:500 14.5px/1.42 system-ui,sans-serif;color:#1b1f24}.yj-rel-p{font:600 13px system-ui,sans-serif;color:#0a6238}</style></section></body>
</html>
|