diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
index a37b01210b5c..ee959bcfedf8 100644
--- a/.github/CONTRIBUTING.md
+++ b/.github/CONTRIBUTING.md
@@ -27,9 +27,6 @@ restrictions:
Use [GitHub's "reactions" feature](https://blog.github.com/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/)
instead. We reserve the right to delete comments which violate this rule.
-- Please **do not** open issues regarding the official themes offered on .
- Instead, please email any questions or feedback regarding those themes to `themes AT getbootstrap DOT com`.
-
## Issues assignment
diff --git a/.github/INCIDENT_RESPONSE.md b/.github/INCIDENT_RESPONSE.md
new file mode 100644
index 000000000000..f3e8f5266ecb
--- /dev/null
+++ b/.github/INCIDENT_RESPONSE.md
@@ -0,0 +1,162 @@
+# Incident response plan
+
+This document describes how the Bootstrap maintainers respond to and manage security or operational incidents affecting the project, its website, or its distributed releases. This plan is public to promote transparency and community trust. Operational details (e.g., private contacts, credentials, or internal coordination tools) are maintained separately in the maintainers’ private documentation.
+
+---
+
+## 1. Purpose & Scope
+
+This plan defines how Bootstrap maintainers will:
+
+- Identify, triage, and manage security or integrity incidents affecting project code, releases, or infrastructure.
+- Communicate with the community and downstream consumers during and after an incident.
+- Record lessons learned and update processes to reduce future risk.
+
+It applies to:
+
+- The Bootstrap source code, documentation, and build pipelines.
+- Release artifacts (npm, CDN, GitHub releases).
+- The main website ([https://getbootstrap.com](https://getbootstrap.com)).
+- Any official Bootstrap GitHub organization infrastructure.
+
+It does **not** cover unrelated third-party forks or integrations.
+
+---
+
+## 2. Definitions
+
+- **Incident**: Any event that could compromise the confidentiality, integrity, or availability of Bootstrap code, releases, or users. Examples include:
+ - A discovered security vulnerability.
+ - A compromised GitHub account or CI/CD token.
+ - A malicious dependency or injected code in a release.
+ - Website defacement or unauthorized modification of documentation.
+ - Leaked secrets related to the project infrastructure.
+
+- **Incident Commander (IC)**: The maintainer responsible for coordinating the overall response.
+
+---
+
+## 3. Roles & Responsibilities
+
+| Role | Responsibilities |
+|------|-------------------|
+| **Incident Commander (IC)** | Coordinate the response, assign tasks, ensure timely communication. |
+| **Security Maintainers** | Triage reported vulnerabilities, assess impact, create fixes, handle embargoes. |
+| **Infrastructure Lead** | Manage CI/CD, website, and release infrastructure. |
+| **Communications Lead** | Manage public announcements, blog posts, and social updates. |
+| **Contributors & Community** | Promptly report suspected security issues and follow responsible disclosure guidelines. |
+
+In practice, Bootstrap’s core team fulfills these roles collectively, assigning an IC on a per-incident basis.
+
+---
+
+## 4. Incident workflow
+
+### 4.1 Detection & Reporting
+
+- All security issues should be **privately reported** via the contact method in [`SECURITY.md`](../SECURITY.md) or through GitHub’s Security Advisory mechanism.
+- Maintainers also monitor:
+ - Automated dependency scanners (e.g., Dependabot, npm audit).
+ - GitHub notifications and vulnerability alerts.
+ - Community channels for suspicious activity.
+
+### 4.2 Initial triage
+
+Upon receiving a report:
+
+1. A maintainer acknowledges receipt within 3 business days (or sooner, when possible).
+ Bootstrap is maintained by a small volunteer team; response times may vary slightly outside normal working hours.
+2. The IC assesses severity and impact:
+ - **Critical:** immediate compromise of release infrastructure or code integrity.
+ - **High:** exploitable vulnerability in distributed assets.
+ - **Medium:** minor vulnerability or low-likelihood attack vector.
+ - **Low:** informational, no direct risk.
+3. If confirmed as an incident, the IC opens a private coordination channel for maintainers and begins containment.
+
+### 4.3 Containment & Eradication
+
+- Revoke or rotate any affected credentials.
+- Disable compromised infrastructure or build pipelines if necessary.
+- Patch affected branches or dependencies.
+- Verify integrity of artifacts and releases.
+
+### 4.4 Communication
+
+- Keep the reporting party informed (when applicable).
+- For major incidents, the Communications Lead drafts a public advisory describing:
+ - What happened
+ - What was impacted
+ - How users can verify or mitigate
+ - What actions were taken
+- Communications occur after containment to avoid amplifying risk.
+
+Public disclosures are posted via:
+
+- GitHub Security Advisory if appropriate
+- [blog.getbootstrap.com/](https://blog.getbootstrap.com/)
+- [Bootstrap GitHub discussions](https://github.com/orgs/twbs/discussions)
+- [@getbootstrap](https://x.com/getbootstrap) on X (formerly Twitter) for critical security notices.
+
+### 4.5 Recovery
+
+- Validate all systems and releases are secure.
+- Resume normal operations.
+- Tag patched releases and notify affected users.
+
+### 4.6 Post-incident review
+
+Within two weeks after resolution:
+
+- Conduct an internal debrief.
+- Record:
+ - Root cause
+ - What worked / what didn’t
+ - Remediation steps
+ - Documentation or automation updates needed
+- Summarize lessons learned in the private maintainers’ wiki (with optional public summary if appropriate).
+
+---
+
+## 5. Severity levels & Response targets
+
+| Severity | Example | Target response (volunteer team) |
+|-----------|----------|----------------------------------|
+| **Critical** | Compromised release, stolen signing keys | Acknowledge ≤ 24h (best effort), containment ≤ 48h, fix ideally ≤ 14d |
+| **High** | Vulnerability enabling arbitrary code execution | Acknowledge ≤ 3 business days, fix ideally ≤ 14–21d |
+| **Medium** | XSS or content injection on docs site | Acknowledge ≤ 5 business days, fix in next release cycle |
+| **Low** | Minor issue with limited risk | Acknowledge ≤ 7 business days, fix as scheduled |
+
+**Note:** Timelines represent good-faith targets for a small volunteer core team, not hard SLAs. The maintainers will always prioritize public safety and transparency, even if timing varies.
+
+---
+
+## 6. Public disclosure principles
+
+Bootstrap follows a responsible disclosure approach:
+
+- Work privately with reporters and affected parties before publishing details.
+- Never name reporters without consent.
+- Coordinate embargo periods with downstream consumers when needed.
+- Publish advisories only after patches or mitigations are available.
+
+---
+
+## 7. Communication Channels
+
+| Purpose | Channel |
+|----------|----------|
+| Private reporting | Email address in [`SECURITY.md`](./SECURITY.md) or GitHub advisory form |
+| General updates | [blog.getbootstrap.com/](https://blog.getbootstrap.com/) blog |
+| Security advisories | GitHub Security Advisory dashboard |
+| Social alerts | [@getbootstrap](https://x.com/getbootstrap) |
+| GitHub discussion alerts | [github.com/orgs/twbs/discussions](https://github.com/orgs/twbs/discussions) |
+
+---
+
+## 8. Plan Maintenance
+
+This plan is reviewed at least annually or after any major incident. Changes are approved by the Core Team and recorded in Git history.
+
+---
+
+_The Bootstrap maintainers are committed to transparency, user trust, and continuous improvement in our security and response practices._
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 77d364498f50..138a4465c7ed 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -7,6 +7,10 @@ updates:
day: tuesday
time: "12:00"
timezone: Europe/Athens
+ groups:
+ github-actions:
+ patterns:
+ - "*"
- package-ecosystem: npm
directory: "/"
labels:
diff --git a/.github/workflows/browserstack.yml b/.github/workflows/browserstack.yml
index a53c233cc671..16bd7a914d54 100644
--- a/.github/workflows/browserstack.yml
+++ b/.github/workflows/browserstack.yml
@@ -9,7 +9,7 @@ on:
env:
FORCE_COLOR: 2
- NODE: 20
+ NODE: 22
permissions:
contents: read
@@ -22,12 +22,12 @@ jobs:
steps:
- name: Clone repository
- uses: actions/checkout@v4
+ uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- name: Set up Node.js
- uses: actions/setup-node@v4
+ uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
with:
node-version: "${{ env.NODE }}"
cache: npm
diff --git a/.github/workflows/bundlewatch.yml b/.github/workflows/bundlewatch.yml
index 99ba06063414..e490be150162 100644
--- a/.github/workflows/bundlewatch.yml
+++ b/.github/workflows/bundlewatch.yml
@@ -9,7 +9,7 @@ on:
env:
FORCE_COLOR: 2
- NODE: 20
+ NODE: 22
permissions:
contents: read
@@ -20,12 +20,12 @@ jobs:
steps:
- name: Clone repository
- uses: actions/checkout@v4
+ uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- name: Set up Node.js
- uses: actions/setup-node@v4
+ uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
with:
node-version: "${{ env.NODE }}"
cache: npm
diff --git a/.github/workflows/calibreapp-image-actions.yml b/.github/workflows/calibreapp-image-actions.yml
index 08987b3aae69..0f56922d3905 100644
--- a/.github/workflows/calibreapp-image-actions.yml
+++ b/.github/workflows/calibreapp-image-actions.yml
@@ -22,11 +22,11 @@ jobs:
pull-requests: write
steps:
- name: Clone repository
- uses: actions/checkout@v4
+ uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- name: Compress Images
- uses: calibreapp/image-actions@1.1.0
+ uses: calibreapp/image-actions@f32575787d333b0579f0b7d506ff03be63a669d1 # v1.4.1
with:
- githubToken: ${{ secrets.GITHUB_TOKEN }}
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
index dd7f6e7ef8d5..015ed85e18ac 100644
--- a/.github/workflows/codeql.yml
+++ b/.github/workflows/codeql.yml
@@ -24,21 +24,21 @@ jobs:
steps:
- name: Checkout repository
- uses: actions/checkout@v4
+ uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- name: Initialize CodeQL
- uses: github/codeql-action/init@v3
+ uses: github/codeql-action/init@cf1bb45a277cb3c205638b2cd5c984db1c46a412 # v4.31.7
with:
config-file: ./.github/codeql/codeql-config.yml
languages: "javascript"
queries: +security-and-quality
- name: Autobuild
- uses: github/codeql-action/autobuild@v3
+ uses: github/codeql-action/autobuild@cf1bb45a277cb3c205638b2cd5c984db1c46a412 # v4.31.7
- name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@v3
+ uses: github/codeql-action/analyze@cf1bb45a277cb3c205638b2cd5c984db1c46a412 # v4.31.7
with:
category: "/language:javascript"
diff --git a/.github/workflows/cspell.yml b/.github/workflows/cspell.yml
index 44eb025fd845..038aebe20f7e 100644
--- a/.github/workflows/cspell.yml
+++ b/.github/workflows/cspell.yml
@@ -23,12 +23,12 @@ jobs:
steps:
- name: Clone repository
- uses: actions/checkout@v4
+ uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- name: Run cspell
- uses: streetsidesoftware/cspell-action@v7
+ uses: streetsidesoftware/cspell-action@3294df585d3d639e30f3bc019cb11940b9866e95 # v8.0.0
with:
config: ".cspell.json"
files: "**/*.{md,mdx}"
diff --git a/.github/workflows/css.yml b/.github/workflows/css.yml
index 52e93e2b2354..30d1d87b057d 100644
--- a/.github/workflows/css.yml
+++ b/.github/workflows/css.yml
@@ -9,7 +9,7 @@ on:
env:
FORCE_COLOR: 2
- NODE: 20
+ NODE: 22
permissions:
contents: read
@@ -20,12 +20,12 @@ jobs:
steps:
- name: Clone repository
- uses: actions/checkout@v4
+ uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- name: Set up Node.js
- uses: actions/setup-node@v4
+ uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
with:
node-version: "${{ env.NODE }}"
cache: npm
diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
index 082220563791..7cbb3ad5b9eb 100644
--- a/.github/workflows/docs.yml
+++ b/.github/workflows/docs.yml
@@ -9,7 +9,7 @@ on:
env:
FORCE_COLOR: 2
- NODE: 20
+ NODE: 22
permissions:
contents: read
@@ -20,12 +20,12 @@ jobs:
steps:
- name: Clone repository
- uses: actions/checkout@v4
+ uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- name: Set up Node.js
- uses: actions/setup-node@v4
+ uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
with:
node-version: "${{ env.NODE }}"
cache: npm
@@ -42,9 +42,9 @@ jobs:
run: npm run docs-vnu
- name: Run linkinator
- uses: JustinBeckwith/linkinator-action@v1
+ uses: JustinBeckwith/linkinator-action@af984b9f30f63e796ae2ea5be5e07cb587f1bbd9 # v2.3
with:
paths: _site
recurse: true
verbosity: error
- skip: "^(?!http://localhost)"
+ skip: "^http://localhost"
diff --git a/.github/workflows/issue-close-require.yml b/.github/workflows/issue-close-require.yml
index b5000d8b4350..701c329d2610 100644
--- a/.github/workflows/issue-close-require.yml
+++ b/.github/workflows/issue-close-require.yml
@@ -17,7 +17,7 @@ jobs:
if: github.repository == 'twbs/bootstrap'
steps:
- name: awaiting reply
- uses: actions-cool/issues-helper@v3
+ uses: actions-cool/issues-helper@3809910bc12872edc9b8132f122069ac16cd16ee # v3.7.3
with:
actions: "close-issues"
labels: "awaiting-reply"
diff --git a/.github/workflows/issue-labeled.yml b/.github/workflows/issue-labeled.yml
index 584879dd80cf..6c8c1f2dafd1 100644
--- a/.github/workflows/issue-labeled.yml
+++ b/.github/workflows/issue-labeled.yml
@@ -18,7 +18,7 @@ jobs:
steps:
- name: awaiting reply
if: github.event.label.name == 'needs-example'
- uses: actions-cool/issues-helper@v3
+ uses: actions-cool/issues-helper@3809910bc12872edc9b8132f122069ac16cd16ee # v3.7.3
with:
actions: "create-comment"
token: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/js.yml b/.github/workflows/js.yml
index 1b672aa3097f..40bb7c17b58a 100644
--- a/.github/workflows/js.yml
+++ b/.github/workflows/js.yml
@@ -9,7 +9,7 @@ on:
env:
FORCE_COLOR: 2
- NODE: 20
+ NODE: 22
permissions:
contents: read
@@ -25,12 +25,12 @@ jobs:
steps:
- name: Clone repository
- uses: actions/checkout@v4
+ uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- name: Set up Node.js
- uses: actions/setup-node@v4
+ uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
with:
node-version: ${{ env.NODE }}
cache: npm
@@ -45,7 +45,7 @@ jobs:
run: npm run js-test
- name: Run Coveralls
- uses: coverallsapp/github-action@v2
+ uses: coverallsapp/github-action@5cbfd81b66ca5d10c19b062c04de0199c215fb6e # v2.3.7
if: ${{ !github.event.repository.fork }}
with:
github-token: "${{ secrets.GITHUB_TOKEN }}"
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index 213f9ec65909..d69cbbb8d330 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -9,7 +9,7 @@ on:
env:
FORCE_COLOR: 2
- NODE: 20
+ NODE: 22
permissions:
contents: read
@@ -20,12 +20,12 @@ jobs:
steps:
- name: Clone repository
- uses: actions/checkout@v4
+ uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- name: Set up Node.js
- uses: actions/setup-node@v4
+ uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
with:
node-version: "${{ env.NODE }}"
cache: npm
diff --git a/.github/workflows/node-sass.yml b/.github/workflows/node-sass.yml
index 493cc35fde98..791d1a971773 100644
--- a/.github/workflows/node-sass.yml
+++ b/.github/workflows/node-sass.yml
@@ -9,7 +9,7 @@ on:
env:
FORCE_COLOR: 2
- NODE: 20
+ NODE: 22
permissions:
contents: read
@@ -20,12 +20,12 @@ jobs:
steps:
- name: Clone repository
- uses: actions/checkout@v4
+ uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- name: Set up Node.js
- uses: actions/setup-node@v4
+ uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
with:
node-version: "${{ env.NODE }}"
diff --git a/.github/workflows/publish-nuget.yml b/.github/workflows/publish-nuget.yml
new file mode 100644
index 000000000000..5a6c1af18c6c
--- /dev/null
+++ b/.github/workflows/publish-nuget.yml
@@ -0,0 +1,34 @@
+name: Publish NuGet Packages
+
+on:
+ release:
+ types: [published]
+
+permissions:
+ contents: read
+
+jobs:
+ package-nuget:
+ runs-on: windows-latest
+ if: ${{ github.repository == 'twbs/bootstrap' && startsWith(github.event.release.tag_name, 'v') }}
+ env:
+ GITHUB_REF_NAME: ${{ github.ref_name }}
+ steps:
+ - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
+ with:
+ persist-credentials: false
+
+ - name: Set up NuGet
+ uses: nuget/setup-nuget@323ab0502cd38fdc493335025a96c8fdb0edc71f # v2.0.1
+ with:
+ nuget-api-key: ${{ secrets.NuGetAPIKey }}
+ nuget-version: '5.x'
+
+ - name: Pack NuGet packages
+ shell: pwsh
+ run: |
+ $bsversion = $env:GITHUB_REF_NAME.Substring(1)
+ nuget pack "nuget\bootstrap.nuspec" -Verbosity detailed -NonInteractive -BasePath . -Version $bsversion
+ nuget pack "nuget\bootstrap.sass.nuspec" -Verbosity detailed -NonInteractive -BasePath . -Version $bsversion
+ nuget push "bootstrap.$bsversion.nupkg" -Verbosity detailed -NonInteractive -Source "https://api.nuget.org/v3/index.json"
+ nuget push "bootstrap.sass.$bsversion.nupkg" -Verbosity detailed -NonInteractive -Source "https://api.nuget.org/v3/index.json"
diff --git a/.github/workflows/release-notes.yml b/.github/workflows/release-notes.yml
index 813956af2033..d37d5e84120c 100644
--- a/.github/workflows/release-notes.yml
+++ b/.github/workflows/release-notes.yml
@@ -18,6 +18,6 @@ jobs:
runs-on: ubuntu-latest
if: github.repository == 'twbs/bootstrap'
steps:
- - uses: release-drafter/release-drafter@v6
+ - uses: release-drafter/release-drafter@b1476f6e6eb133afa41ed8589daba6dc69b4d3f5 # v6.1.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml
new file mode 100644
index 000000000000..8b65297a071e
--- /dev/null
+++ b/.github/workflows/scorecard.yml
@@ -0,0 +1,78 @@
+# This workflow uses actions that are not certified by GitHub. They are provided
+# by a third-party and are governed by separate terms of service, privacy
+# policy, and support documentation.
+
+name: Scorecard supply-chain security
+on:
+ # For Branch-Protection check. Only the default branch is supported. See
+ # https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection
+ branch_protection_rule:
+ # To guarantee Maintained check is occasionally updated. See
+ # https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained
+ schedule:
+ - cron: '27 12 * * 2'
+ push:
+ branches: [ "main" ]
+
+# Declare default permissions as read only.
+permissions: read-all
+
+jobs:
+ analysis:
+ name: Scorecard analysis
+ runs-on: ubuntu-latest
+ # `publish_results: true` only works when run from the default branch. conditional can be removed if disabled.
+ if: github.event.repository.default_branch == github.ref_name || github.event_name == 'pull_request'
+ permissions:
+ # Needed to upload the results to code-scanning dashboard.
+ security-events: write
+ # Needed to publish results and get a badge (see publish_results below).
+ id-token: write
+ # Uncomment the permissions below if installing in a private repository.
+ # contents: read
+ # actions: read
+
+ steps:
+ - name: "Checkout code"
+ uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
+ with:
+ persist-credentials: false
+
+ - name: "Run analysis"
+ uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3
+ with:
+ results_file: results.sarif
+ results_format: sarif
+ # (Optional) "write" PAT token. Uncomment the `repo_token` line below if:
+ # - you want to enable the Branch-Protection check on a *public* repository, or
+ # - you are installing Scorecard on a *private* repository
+ # To create the PAT, follow the steps in https://github.com/ossf/scorecard-action?tab=readme-ov-file#authentication-with-fine-grained-pat-optional.
+ # repo_token: ${{ secrets.SCORECARD_TOKEN }}
+
+ # Public repositories:
+ # - Publish results to OpenSSF REST API for easy access by consumers
+ # - Allows the repository to include the Scorecard badge.
+ # - See https://github.com/ossf/scorecard-action#publishing-results.
+ # For private repositories:
+ # - `publish_results` will always be set to `false`, regardless
+ # of the value entered here.
+ publish_results: true
+
+ # (Optional) Uncomment file_mode if you have a .gitattributes with files marked export-ignore
+ # file_mode: git
+
+ # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
+ # format to the repository Actions tab.
+ - name: "Upload artifact"
+ uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
+ with:
+ name: SARIF file
+ path: results.sarif
+ retention-days: 5
+
+ # Upload the results to GitHub's code scanning dashboard (optional).
+ # Commenting out will disable upload of results to your repo's Code Scanning dashboard
+ - name: "Upload to code-scanning"
+ uses: github/codeql-action/upload-sarif@cf1bb45a277cb3c205638b2cd5c984db1c46a412 # v4.31.7
+ with:
+ sarif_file: results.sarif
diff --git a/.gitignore b/.gitignore
index bb95ca04070c..235ad54948dd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -26,7 +26,6 @@
*.sublime-workspace
nbproject
Thumbs.db
-/.vscode/
# Local Netlify folder
.netlify
diff --git a/.vscode/extensions.json b/.vscode/extensions.json
new file mode 100644
index 000000000000..bc5df00e1618
--- /dev/null
+++ b/.vscode/extensions.json
@@ -0,0 +1,10 @@
+{
+ "recommendations": [
+ "astro-build.astro-vscode",
+ "dbaeumer.vscode-eslint",
+ "EditorConfig.EditorConfig",
+ "hossaini.bootstrap-intellisense",
+ "streetsidesoftware.code-spell-checker",
+ "stylelint.vscode-stylelint"
+ ]
+}
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 000000000000..9c6ae2d622a3
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,10 @@
+{
+ "editor.codeActionsOnSave": {
+ "source.fixAll.eslint": "explicit",
+ "source.fixAll.stylelint": "always"
+ },
+ "editor.renderWhitespace": "all",
+ "scss.validate": false,
+ "stylelint.enable": true,
+ "stylelint.validate": ["scss"]
+}
diff --git a/README.md b/README.md
index b86bd5f8515a..e3618e643e5c 100644
--- a/README.md
+++ b/README.md
@@ -16,8 +16,6 @@
·
Request feature
·
- Themes
- ·
Blog
@@ -46,12 +44,12 @@ Our default branch is for development of our Bootstrap 5 release. Head to the [`
Several quick start options are available:
-- [Download the latest release](https://github.com/twbs/bootstrap/archive/v5.3.6.zip)
+- [Download the latest release](https://github.com/twbs/bootstrap/archive/v5.3.8.zip)
- Clone the repo: `git clone https://github.com/twbs/bootstrap.git`
-- Install with [npm](https://www.npmjs.com/): `npm install bootstrap@v5.3.6`
-- Install with [yarn](https://yarnpkg.com/): `yarn add bootstrap@v5.3.6`
-- Install with [Bun](https://bun.sh/): `bun add bootstrap@v5.3.6`
-- Install with [Composer](https://getcomposer.org/): `composer require twbs/bootstrap:5.3.6`
+- Install with [npm](https://www.npmjs.com/): `npm install bootstrap@v5.3.8`
+- Install with [yarn](https://yarnpkg.com/): `yarn add bootstrap@v5.3.8`
+- Install with [Bun](https://bun.sh/): `bun add bootstrap@v5.3.8`
+- Install with [Composer](https://getcomposer.org/): `composer require twbs/bootstrap:5.3.8`
- Install with [NuGet](https://www.nuget.org/): CSS: `Install-Package bootstrap` Sass: `Install-Package bootstrap.sass`
Read the [Getting started page](https://getbootstrap.com/docs/5.3/getting-started/introduction/) for information on the framework contents, templates, examples, and more.
@@ -70,6 +68,7 @@ Read the [Getting started page](https://getbootstrap.com/docs/5.3/getting-starte
[](https://github.com/twbs/bootstrap/blob/main/dist/css/bootstrap.min.css)
[](https://github.com/twbs/bootstrap/blob/main/dist/js/bootstrap.min.js)
[](https://github.com/twbs/bootstrap/blob/main/dist/js/bootstrap.min.js)
+
[](#backers)
[](#sponsors)
@@ -151,7 +150,7 @@ Documentation search is powered by [Algolia's DocSearch](https://docsearch.algol
1. Run `npm install` to install the Node.js dependencies, including Astro (the site builder).
2. Run `npm run test` (or a specific npm script) to rebuild distributed CSS and JavaScript files, as well as our docs assets.
3. From the root `/bootstrap` directory, run `npm run docs-serve` in the command line.
-4. Open `http://localhost:9001/` in your browser, and voilà.
+4. Open in your browser, and voilà.
Learn more about using Astro by reading its [documentation](https://docs.astro.build/en/getting-started/).
diff --git a/build/docs-prep.sh b/build/docs-prep.sh
index b0054257e7b1..357768abea7a 100755
--- a/build/docs-prep.sh
+++ b/build/docs-prep.sh
@@ -18,6 +18,9 @@ fi
# Branch name to create
NEW_BRANCH="gh-pages-${BRANCH_SUFFIX}"
+# Get the current docs version from config
+DOCS_VERSION=$(node -p "require('js-yaml').load(require('fs').readFileSync('config.yml', 'utf8')).docs_version")
+
# Function to print colored messages
print_success() {
echo -e "${GREEN}✓ $1${NC}"
@@ -89,66 +92,39 @@ fi
print_success "Pulled latest changes from origin/gh-pages"
# Step 4: Create a new branch for the update
+print_info "Checking if branch ${NEW_BRANCH} exists and deleting it if it does…"
+if git show-ref --verify --quiet refs/heads/${NEW_BRANCH}; then
+ execute "git branch -D ${NEW_BRANCH}"
+else
+ print_info "Branch ${NEW_BRANCH} does not exist, proceeding with creation…"
+fi
print_info "Creating new branch ${NEW_BRANCH}…"
execute "git checkout -b ${NEW_BRANCH}"
-# Step 5: Move root files
-print_info "Moving root files from temporary location…"
-ROOT_FILES=("404.html" "CNAME" "apple-touch-icon.png" "favicon.ico" "index.html" "robots.txt" "sitemap-0.xml" "sitemap-index.xml" "sw.js")
-for file in "${ROOT_FILES[@]}"; do
- if [ -f "/tmp/_site/$file" ]; then
- execute "mv /tmp/_site/$file ."
- else
- print_warning "File /tmp/_site/$file not found. Skipping."
- fi
-done
-
-# Step 6: Move directories with cleanup
-print_info "Moving directories from temporary location…"
-DIRS=("about" "components" "docsref" "examples" "getting-started" "migration")
-for dir in "${DIRS[@]}"; do
- if [ -d "/tmp/_site/$dir" ]; then
- if [ -d "$dir" ]; then
- execute "rm -rf $dir"
- fi
- execute "mv /tmp/_site/$dir ."
- else
- print_warning "Directory /tmp/_site/$dir not found. Skipping."
- fi
-done
-
-# Step 7: Handle special doc directories
-print_info "Handling special documentation directories…"
-SPECIAL_DOCS=("docs/getting-started" "docs/versions")
-for dir in "${SPECIAL_DOCS[@]}"; do
- if [ -d "/tmp/_site/$dir" ]; then
- if [ -d "$dir" ]; then
- execute "rm -rf $dir"
- fi
- # Make sure parent directory exists
- parent_dir=$(dirname "$dir")
- mkdir -p "$parent_dir"
- execute "mv /tmp/_site/$dir $parent_dir/"
- else
- print_warning "Directory /tmp/_site/$dir not found. Skipping."
- fi
-done
+# Step 5: Move all root-level files from Astro build
+find /tmp/_site -maxdepth 1 -type f -exec mv {} . \;
-# Step 8: Move docs index.html
-if [ -f "/tmp/_site/docs/index.html" ]; then
- execute "mv /tmp/_site/docs/index.html docs/index.html"
-else
- print_warning "File /tmp/_site/docs/index.html not found. Skipping."
-fi
+# Step 6: Move all top-level directories except 'docs' (which needs special handling)
+find /tmp/_site -maxdepth 1 -type d ! -name "_site" ! -name "docs" -exec sh -c 'dir=$(basename "$1"); rm -rf "$dir"; mv "$1" .' _ {} \;
-# Step 9: Handle docs/5.3
-if [ -d "/tmp/_site/docs/5.3" ]; then
- if [ -d "docs/5.3" ]; then
- execute "rm -rf docs/5.3"
+# Step 7: Handle docs directory specially
+if [ -d "/tmp/_site/docs" ]; then
+ # Replace only the current version's docs
+ if [ -d "docs/$DOCS_VERSION" ]; then
+ rm -rf "docs/$DOCS_VERSION"
fi
- execute "mv /tmp/_site/docs/5.3 docs/"
-else
- print_warning "Directory /tmp/_site/docs/5.3 not found. Skipping."
+ mv "/tmp/_site/docs/$DOCS_VERSION" "docs/"
+
+ # Handle docs root files
+ find /tmp/_site/docs -maxdepth 1 -type f -exec mv {} docs/ \;
+
+ # Handle special docs directories (getting-started, versions)
+ for special_dir in getting-started versions; do
+ if [ -d "/tmp/_site/docs/$special_dir" ]; then
+ rm -rf "docs/$special_dir"
+ mv "/tmp/_site/docs/$special_dir" "docs/"
+ fi
+ done
fi
# Clean up remaining files in /tmp/_site if any
diff --git a/build/zip-examples.mjs b/build/zip-examples.mjs
index e2b5245f1940..6b2e1e0daca9 100644
--- a/build/zip-examples.mjs
+++ b/build/zip-examples.mjs
@@ -11,6 +11,7 @@ import fs from 'node:fs/promises'
import path from 'node:path'
import { fileURLToPath } from 'node:url'
import sh from 'shelljs'
+import { format } from 'prettier'
const __dirname = path.dirname(fileURLToPath(import.meta.url))
@@ -83,16 +84,34 @@ for (const file of staticJsFiles) {
sh.rm(`${distFolder}/index.html`)
// get all examples' HTML files
-for (const file of sh.find(`${distFolder}/**/*.html`)) {
+const htmlFiles = sh.find(`${distFolder}/**/*.html`)
+
+const formatPromises = htmlFiles.map(async file => {
const fileContents = sh.cat(file)
.toString()
.replace(new RegExp(`"/docs/${versionShort}/`, 'g'), '"../')
.replace(/"..\/dist\//g, '"../assets/dist/')
- .replace(/(/g, '$1>')
- .replace(/(')
- .replace(/( +)