From 71257c1b376b685aa7e947d06e28e03c1895b3e8 Mon Sep 17 00:00:00 2001 From: Kyle Lesinger Date: Tue, 18 Nov 2025 16:20:14 -0600 Subject: [PATCH 1/6] Add password protection to PR preview deployments --- .github/workflows/preview.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index 70e9050..1634a26 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -26,6 +26,18 @@ jobs: - run: pip install -r requirements.txt - run: quarto render --to html + - name: Inject password into login page + run: | + # Replace {{SITE_PASSWORD}} with actual password from GitHub secret + if [ -f "_site/password-protect.html" ]; then + sed -i "s/{{SITE_PASSWORD}}/${{ secrets.SITE_PASSWORD }}/g" _site/password-protect.html + echo "Password injected successfully" + else + echo "Warning: password-protect.html not found" + fi + env: + SITE_PASSWORD: ${{ secrets.SITE_PASSWORD }} + - name: Deploy preview uses: rossjrw/pr-preview-action@v1 with: From a8e78d62fe3026d14e368973dd2794e24d8b7c19 Mon Sep 17 00:00:00 2001 From: Kyle Lesinger Date: Tue, 18 Nov 2025 16:32:05 -0600 Subject: [PATCH 2/6] Fix PR preview being overwritten by main deployment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The quarto-publish workflow was triggering on both 'main' and 'addContent' branches. When a PR from addContent was opened, both workflows would run: 1. PR preview workflow would deploy to gh-pages/pr-preview/pr-XX/ 2. Main deployment workflow would then overwrite the entire gh-pages branch Now the workflow only triggers on 'main' branch pushes, allowing PR previews to persist without being overwritten. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .github/workflows/quarto-publish.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/quarto-publish.yml b/.github/workflows/quarto-publish.yml index 2b3efb4..2b0edf1 100644 --- a/.github/workflows/quarto-publish.yml +++ b/.github/workflows/quarto-publish.yml @@ -2,7 +2,6 @@ on: push: branches: - main - - addContent workflow_dispatch: permissions: write-all From 79792ee1e4ea410db0376c98738e56d236da2dac Mon Sep 17 00:00:00 2001 From: Kyle Lesinger Date: Tue, 18 Nov 2025 16:36:44 -0600 Subject: [PATCH 3/6] Fix password protection for PR preview deployments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Updated auth-check.js to use dynamic path resolution instead of hardcoded absolute paths. This ensures that: - Main site redirects to /disasters-docs/password-protect.html - PR previews redirect to /disasters-docs/pr-preview/pr-XX/password-protect.html The getBasePath() function extracts the current directory path and constructs the correct login page URL relative to the current location. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- auth-check.js | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/auth-check.js b/auth-check.js index 66fc7ae..6393e12 100644 --- a/auth-check.js +++ b/auth-check.js @@ -2,6 +2,25 @@ (function() { const SESSION_KEY = 'disasters_docs_auth'; + // Get the base path for the current page + function getBasePath() { + const path = window.location.pathname; + // Extract base directory from current path + const parts = path.split('/').filter(p => p); + // Find the index.html or last segment + const fileIndex = parts.findIndex(p => p.endsWith('.html')); + if (fileIndex > 0) { + return '/' + parts.slice(0, fileIndex).join('/') + '/'; + } + // Default: go to root of disasters-docs + return '/disasters-docs/'; + } + + function getLoginPage() { + const basePath = getBasePath(); + return basePath + 'password-protect.html'; + } + function checkAuth() { // Skip authentication on localhost (for development) if (window.location.hostname === 'localhost' || @@ -20,7 +39,7 @@ if (!auth) { // No authentication, redirect to login - window.location.href = '/disasters-docs/password-protect.html'; + window.location.href = getLoginPage(); return; } @@ -31,7 +50,7 @@ if (authData.expires <= now || !authData.authenticated) { // Expired or invalid session localStorage.removeItem(SESSION_KEY); - window.location.href = '/disasters-docs/password-protect.html'; + window.location.href = getLoginPage(); return; } @@ -39,7 +58,7 @@ } catch (e) { // Invalid auth data localStorage.removeItem(SESSION_KEY); - window.location.href = '/disasters-docs/password-protect.html'; + window.location.href = getLoginPage(); } } @@ -57,7 +76,7 @@ logoutBtn.style.cssText = 'position: fixed; top: 10px; right: 10px; padding: 8px 16px; background: #e74c3c; color: white; border: none; border-radius: 5px; cursor: pointer; z-index: 9999; font-size: 14px;'; logoutBtn.onclick = function() { localStorage.removeItem(SESSION_KEY); - window.location.href = '/disasters-docs/password-protect.html'; + window.location.href = getLoginPage(); }; document.body.appendChild(logoutBtn); } From 1a72f076a29fdd299de92fbe6ae9fa529e1a573f Mon Sep 17 00:00:00 2001 From: Kyle Lesinger Date: Tue, 18 Nov 2025 16:44:34 -0600 Subject: [PATCH 4/6] Inline authentication script to ensure password protection works MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ISSUE: The auth-check.js external script was not being included in deployed HTML pages on PR previews, causing authentication to fail. SOLUTION: 1. Inlined the entire auth-check.js content directly in _quarto.yml under include-in-header. This ensures the script is always embedded in every rendered HTML page. 2. Added verification step to both workflows (preview.yml and quarto-publish.yml) that checks for the presence of the auth script in rendered HTML before deployment. Build fails if script is missing. This guarantees password protection works on all deployments: - Main site (disasters-docs/) - PR previews (disasters-docs/pr-preview/pr-XX/) - Any future branch deployments 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .github/workflows/preview.yml | 9 +++ .github/workflows/quarto-publish.yml | 9 +++ _quarto.yml | 87 +++++++++++++++++++++++++++- 3 files changed, 104 insertions(+), 1 deletion(-) diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index 1634a26..2a06e30 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -26,6 +26,15 @@ jobs: - run: pip install -r requirements.txt - run: quarto render --to html + - name: Verify auth script is present in rendered HTML + run: | + if grep -q "disasters_docs_auth" _site/index.html; then + echo "✓ Authentication script found in rendered HTML" + else + echo "✗ ERROR: Authentication script not found in rendered HTML" + exit 1 + fi + - name: Inject password into login page run: | # Replace {{SITE_PASSWORD}} with actual password from GitHub secret diff --git a/.github/workflows/quarto-publish.yml b/.github/workflows/quarto-publish.yml index 2b0edf1..834c1a3 100644 --- a/.github/workflows/quarto-publish.yml +++ b/.github/workflows/quarto-publish.yml @@ -29,6 +29,15 @@ jobs: - run: pip install -r requirements.txt - run: quarto render --to html + - name: Verify auth script is present in rendered HTML + run: | + if grep -q "disasters_docs_auth" _site/index.html; then + echo "✓ Authentication script found in rendered HTML" + else + echo "✗ ERROR: Authentication script not found in rendered HTML" + exit 1 + fi + - name: Inject password into login page run: | # Replace {{SITE_PASSWORD}} with actual password from GitHub secret diff --git a/_quarto.yml b/_quarto.yml index 666d7e0..bd48342 100644 --- a/_quarto.yml +++ b/_quarto.yml @@ -107,6 +107,91 @@ format: toc-depth: 3 include-in-header: - text: | - + filters: - quarto From ecb55c75eea9ada50303e53acacdcb11f9019eaf Mon Sep 17 00:00:00 2001 From: Kyle Lesinger Date: Tue, 18 Nov 2025 16:51:09 -0600 Subject: [PATCH 5/6] Fix getBasePath() to handle directory URLs without .html extension MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ISSUE: When visiting URLs like /disasters-docs/pr-preview/pr-37/ (without index.html), the getBasePath() function couldn't find .html in the path, so it fell back to the default /disasters-docs/, causing incorrect redirects to the wrong password-protect.html location. SOLUTION: Simplified getBasePath() to handle three cases: 1. Path ends with / → it's already the base directory 2. Path ends with .html → extract directory by removing filename 3. Otherwise → assume it's a directory, add trailing slash This ensures correct redirects for all URL formats: - /disasters-docs/pr-preview/pr-37/ → /disasters-docs/pr-preview/pr-37/password-protect.html - /disasters-docs/pr-preview/pr-37/index.html → /disasters-docs/pr-preview/pr-37/password-protect.html - /disasters-docs/ → /disasters-docs/password-protect.html 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- _site/_quarto.yml | 194 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 194 insertions(+) create mode 100644 _site/_quarto.yml diff --git a/_site/_quarto.yml b/_site/_quarto.yml new file mode 100644 index 0000000..aeebefa --- /dev/null +++ b/_site/_quarto.yml @@ -0,0 +1,194 @@ +project: + type: website + resources: + - password-protect.html + - auth-check.js + +website: + page-navigation: true + back-to-top-navigation: true + title: "NASA Disasters Documentation" + site-url: "https://us-ghg-center.github.io/ghgc-docs" #should I change these + repo-url: https://github.com/us-ghg-center/ghgc-docs + repo-actions: [edit, issue] + + page-footer: + right: "This page is built with [Quarto](https://quarto.org/)." + left: "© CC-By US GHG Center, 2022-2023" #how should I change this + + sidebar: + logo: "logo/disasters_logo.png" + pinned: true + align: center + tools: + # - icon: info-circle + # href: https://www.earthdata.nasa.gov/esds/veda + # text: "earthdata.nasa.gov/esds/veda" + - icon: globe-americas + href: https://disasters.openveda.cloud/ + text: "NASA Disasters Portal" + - icon: github + href: https://github.com/Disasters-Learning-Portal + text: "Repository home" + + style: "docked" + search: true + collapse-level: 1 + contents: + - href: index.qmd + text: Welcome + - section: aws.qmd + text: AWS + contents: + - AWS/AWS_SSO_Setup_Guide.qmd + - AWS/AWS_SSO_Remote_Server.qmd + - AWS/aws-mfa-setup.qmd + - AWS/aws-s3-commands-guide.qmd + - section: git-github-comprehensive-guide.qmd + text: GitHub + contents: + - text: "The VEDA Project" + href: GitHub/veda-preview.qmd + - GitHub/setup.qmd + - GitHub/commands.qmd + - GitHub/resources.qmd + - section: jupyterhub.qmd + text: JupyterHub + contents: + - Jupyterhub/jupyterhub-training-guide.qmd + - Jupyterhub/setup-disaster-repo.qmd + - Jupyterhub/convert_to_geotiff.qmd + - Jupyterhub/simple_disaster_template.ipynb + - section: workflow2.qmd + text: Data Workflow Diagrams + contents: + - data_workflow2/NRT_data_download.qmd + - data_workflow2/NRT_directory_structure.qmd + - section: Documentation + contents: + - text: "Quarto Guide for Beginners" + href: quarto-guide.qmd + - section: User Services + contents: + - services/apis.qmd + - services/jupyterhub.qmd + - section: Presentations + contents: + - section: PowerPoints + contents: + - text: "Disasters Logo and Template Overview" + href: Presentations/disasters-powerpoint-template.qmd + - text: "AWS and Grafana Monitoring Tutorial" + href: Presentations/aws-grafana-tutorial.qmd + - text: "JupyterHub and Data Conversions Tutorial" + href: Presentations/jupyterhub-data-conversions-tutorial.qmd + - text: "STAC Database and Apache Airflow Tutorial" + href: Presentations/stac-airflow-tutorial.qmd + # - href: datausage.qmd + # text: Data Usage Notebooks + # - href: datatransformation.qmd + # text: Data Transformation Documentation + # - href: processingreport.qmd + # text: Processing and Verification Reports + # - href: workflow.qmd + # text: Data Workflow + # - href: advanceduser.qmd + # text: Advanced User Notebooks + - section: datausage.qmd + text: Data Usage Notebooks + contents: + - section: Disaster Case Studies + contents: + - text: "Texas Flood 2025" + href: user_data_notebooks/Texas_Flood_2025.ipynb + - text: "New Mexico Fire 2025" + href: user_data_notebooks/New_Mexico_Fire_2025.ipynb + - section: Community-Contributed Tutorials + contents: + - section: datatransformationcode.qmd + text: Data Transformation Notebooks + contents: + - cog_transformation/eccodarwin-co2flux-monthgrid-v5.ipynb + - text: Atmospheric Carbon Dioxide and Methane Concentrations from the NOAA Global Monitoring Laboratory + href: cog_transformation/noaa-gggrn-concentrations.ipynb + - cog_transformation/influx-testbed-ghg-concentrations.ipynb + - cog_transformation/lam-testbed-ghg-concentrations.ipynb + - cog_transformation/nec-testbed-ghg-concentrations.ipynb + - cog_transformation/ct-ch4-monthgrid-v2023.ipynb + - cog_transformation/emit-ch4plume-v1.ipynb + - cog_transformation/goes-ch4plume-v1.ipynb + - cog_transformation/gosat-based-ch4budget-yeargrid-v1.ipynb + - cog_transformation/gra2pes-ghg-monthgrid-v1.ipynb + - cog_transformation/oco2geos-co2-daygrid-v10r.ipynb + - cog_transformation/oco2-mip-co2budget-yeargrid-v1.ipynb + - cog_transformation/odiac-ffco2-monthgrid-v2024.ipynb + - text: "SEDAC Gridded World Population Density" + href: cog_transformation/sedac-popdensity-yeargrid5yr-v4.11.ipynb + - cog_transformation/epa-ch4emission-grid-v2express.ipynb + - cog_transformation/vulcan-ffco2-yeargrid-v4.ipynb + - section: processingreport.qmd + text: Processing and Verification Reports + contents: + - processing_and_verification_reports/eccodarwin-co2flux-monthgrid-v5_Processing and Verification Report.qmd + - text: "Atmospheric Carbon Dioxide Concentrations from the NOAA Global Monitoring Laboratory" + href: processing_and_verification_reports/noaa-gggrn-co2-concentrations_Processing and Verification Report.qmd + - processing_and_verification_reports/noaa-gggrn-ch4-concentrations_Processing and Verification Report.qmd + - processing_and_verification_reports/influx-testbed-ghg-concentrations_Processing and Verification Report.qmd + - processing_and_verification_reports/lam-testbed-ghg-concentrations_Processing and Verification Report.qmd + - processing_and_verification_reports/nec-testbed-ghg-concentrations_Processing and Verification Report.qmd + - processing_and_verification_reports/ct-ch4-monthgrid-v2023_Processing and Verification Report.qmd + - processing_and_verification_reports/emit-ch4plume-v1_Processing and Verification Report.qmd + - processing_and_verification_reports/goes-ch4plume-v1_Processing and Verification Report.qmd + - processing_and_verification_reports/gosat-based-ch4budget-yeargrid-v1_Processing and Verification Report.qmd + - processing_and_verification_reports/gra2pes-ghg-monthgrid-v1_Processing and Verification Report.qmd + - processing_and_verification_reports/micasa-carbonflux-daygrid-v1_Processing and Verification Report.qmd + - processing_and_verification_reports/oco2geos-co2-daygrid-v10r_Processing and Verification Report.qmd + - processing_and_verification_reports/oco2-mip-co2budget-yeargrid-v1_Processing and Verification Report.qmd + - processing_and_verification_reports/odiac-ffco2-monthgrid-v2024_Processing and Verification Report.qmd + - processing_and_verification_reports/sedac-popdensity-yeargrid5yr-v4.11_Processing and Verification Report.qmd + - processing_and_verification_reports/epa-ch4emission-grid-v2express_Processing and Verification Report.qmd + - processing_and_verification_reports/vulcan-ffco2-yeargrid-v4_Processing and Verification Report.qmd + - processing_and_verification_reports/lpjeosim-wetlandch4-grid-v1_Processing and Verification Report.qmd + - section: workflow.qmd + text: Data Flow Diagrams + contents: + - data_workflow/eccodarwin-co2flux-monthgrid-v5_Data_Flow.qmd + - data_workflow/noaa-gggrn-co2-concentrations_Data_Flow.qmd + - data_workflow/noaa-gggrn-ch4-concentrations_Data_Flow.qmd + - data_workflow/influx-testbed-ghg-concentrations_Data_Flow.qmd + - data_workflow/lam-testbed-ghg-concentrations_Data_Flow.qmd + - data_workflow/nec-testbed-ghg-concentrations_Data_Flow.qmd + - data_workflow/ct-ch4-monthgrid-v2023_Data_Flow.qmd + - data_workflow/emit-ch4plume-v1_Data_Flow.qmd + - data_workflow/goes-ch4plume-v1_Data_Flow.qmd + - data_workflow/gosat-based-ch4budget-yeargrid-v1_Data_Flow.qmd + - data_workflow/gra2pes-ghg-monthgrid-v1_Data_Flow.qmd + - data_workflow/micasa-carbonflux-daygrid-v1_Data_Flow.qmd + - data_workflow/oco2geos-co2-daygrid-v10r_Data_Flow.qmd + - data_workflow/oco2-mip-co2budget-yeargrid-v1_Data_Flow.qmd + - data_workflow/odiac-ffco2-monthgrid-v2024_Data_Flow.qmd + - text: "SEDAC Gridded World Population Density" + href: data_workflow/sedac-popdensity-yeargrid5yr-v4.11_Data_Flow.qmd + - text: "U.S. Gridded Anthropogenic Methane Emissions Inventory" + href: data_workflow/epa-ch4emission-grid-v2express_Data_Flow.qmd + - data_workflow/vulcan-ffco2-yeargrid-v4_Data_Flow.qmd + - data_workflow/lpjeosim-wetlandch4-grid-v1_Data_Flow.qmd + +format: + html: + grid: + sidebar-width: 25vw + body-width: 900px + theme: + light: [flatly] + dark: [darkly] + css: styles.css + code-copy: true + code-overflow: wrap + toc: true + toc-depth: 3 + include-in-header: + - text: | + +filters: + - quarto From 98fb0aefa2672aff4b339065a298a1657954e18f Mon Sep 17 00:00:00 2001 From: Kyle Lesinger Date: Tue, 18 Nov 2025 17:13:27 -0600 Subject: [PATCH 6/6] update --- _quarto.yml | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/_quarto.yml b/_quarto.yml index bd48342..346774d 100644 --- a/_quarto.yml +++ b/_quarto.yml @@ -114,16 +114,21 @@ format: // Get the base path for the current page function getBasePath() { - const path = window.location.pathname; - // Extract base directory from current path - const parts = path.split('/').filter(p => p); - // Find the index.html or last segment - const fileIndex = parts.findIndex(p => p.endsWith('.html')); - if (fileIndex > 0) { - return '/' + parts.slice(0, fileIndex).join('/') + '/'; + let path = window.location.pathname; + + // If path ends with / or is a directory, it's already the base + if (path.endsWith('/')) { + return path; + } + + // If path ends with .html, get the directory + if (path.endsWith('.html')) { + const lastSlash = path.lastIndexOf('/'); + return path.substring(0, lastSlash + 1); } - // Default: go to root of disasters-docs - return '/disasters-docs/'; + + // Otherwise, assume it's a directory and add trailing slash + return path + '/'; } function getLoginPage() {