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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 98 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
name: CI

on:
pull_request:
push:
branches:
- main
- codex/**

jobs:
jekyll-build:
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: '3.2'
bundler-cache: true

- name: Build site
run: bundle exec jekyll build

- name: Validate local links in generated HTML
run: |
python3 - <<'PY'
import re
import sys
from pathlib import Path

root = Path('_site')
html_files = [
root / 'index.html',
root / '404.html',
root / 'online-passive-scanner' / 'index.html',
root / 'online-passive-scanner' / 'report.html',
]
missing_html = [str(p) for p in html_files if not p.exists()]
if missing_html:
print('Missing generated HTML:', ', '.join(missing_html))
sys.exit(1)

pattern = re.compile(r'(?:href|src)=["\']([^"\']+)["\']')
missing_targets = []
ignore_exact = {
'link',
'link_to_plugin',
}
ignore_regex = [
re.compile(r'^http__.+\.html$'),
]

for html_file in html_files:
text = html_file.read_text(encoding='utf-8')
for target in pattern.findall(text):
if target.startswith((
'http://',
'https://',
'mailto:',
'tel:',
'javascript:',
'data:',
'#',
'//',
)):
continue

normalized = target.split('#', 1)[0].split('?', 1)[0]
if not normalized:
continue

if normalized in ignore_exact:
continue

if any(regex.match(normalized) for regex in ignore_regex):
continue

if normalized.startswith('/'):
candidate = root / normalized[1:]
else:
candidate = html_file.parent / normalized

if not candidate.exists():
missing_targets.append((str(html_file), target))

if missing_targets:
print('Missing local targets referenced in generated HTML:')
for source, target in missing_targets[:100]:
print(f' {source} -> {target}')
if len(missing_targets) > 100:
print(f' ... and {len(missing_targets) - 100} more')
sys.exit(1)

print('Generated HTML link validation passed.')
PY
53 changes: 53 additions & 0 deletions .github/workflows/deploy-pages.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
name: Deploy GitHub Pages

on:
push:
branches:
- main
workflow_dispatch:

permissions:
contents: read
pages: write
id-token: write

concurrency:
group: pages
cancel-in-progress: true

jobs:
build:
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: '3.2'
bundler-cache: true

- name: Build site
run: bundle exec jekyll build

- name: Setup Pages
uses: actions/configure-pages@v5

- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: _site

deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: build

steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
11 changes: 11 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
_site/
.sass-cache/
.jekyll-cache/
.jekyll-metadata
_next/*
!_next/.keep
out/
index.txt
vendor/
.bundle/
.DS_Store
1 change: 1 addition & 0 deletions .ruby-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.2.2
12 changes: 11 additions & 1 deletion 404.html
Original file line number Diff line number Diff line change
@@ -1 +1,11 @@
<!DOCTYPE html><html lang="en" class="__variable_f367f3"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="preload" href="/_next/static/media/e4af272ccee01ff0-s.p.woff2" as="font" crossorigin="" type="font/woff2"/><link rel="stylesheet" href="/_next/static/css/768a1f78c5edc3c1.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/webpack-b0077c67f4561860.js"/><script src="/_next/static/chunks/fd9d1056-2821b0f0cabcd8bd.js" async=""></script><script src="/_next/static/chunks/23-bc0704c1190bca24.js" async=""></script><script src="/_next/static/chunks/main-app-5dba37e76ac1beef.js" async=""></script><meta name="robots" content="noindex"/><title>404: This page could not be found.</title><title>OWTF — Offensive Web Testing Framework</title><meta name="description" content="OWTF automates the uncreative part of web security testing so assessors can focus on insight, supporting OWASP, NIST, and PTES methodologies."/><meta name="next-size-adjust"/><script src="/_next/static/chunks/polyfills-78c92fac7aa8fdd8.js" noModule=""></script></head><body class="relative min-h-screen bg-background text-slate-900"><div class="pointer-events-none absolute inset-x-0 top-0 -z-10 h-[420px] bg-gradient-to-b from-slate-100 via-white to-white"></div><div class="relative flex min-h-screen flex-col"><div style="font-family:system-ui,&quot;Segoe UI&quot;,Roboto,Helvetica,Arial,sans-serif,&quot;Apple Color Emoji&quot;,&quot;Segoe UI Emoji&quot;;height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div><style>body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding:0 23px 0 0;font-size:24px;font-weight:500;vertical-align:top;line-height:49px">404</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:49px;margin:0">This page could not be found.</h2></div></div></div></div><script src="/_next/static/chunks/webpack-b0077c67f4561860.js" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0]);self.__next_f.push([2,null])</script><script>self.__next_f.push([1,"1:HL[\"/_next/static/media/e4af272ccee01ff0-s.p.woff2\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/woff2\"}]\n2:HL[\"/_next/static/css/768a1f78c5edc3c1.css\",\"style\"]\n"])</script><script>self.__next_f.push([1,"3:I[5751,[],\"\"]\n5:I[9275,[],\"\"]\n6:I[1343,[],\"\"]\nc:I[6130,[],\"\"]\n7:{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"}\n8:{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"}\n9:{\"display\":\"inline-block\"}\na:{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0}\nd:[]\n"])</script><script>self.__next_f.push([1,"0:[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/css/768a1f78c5edc3c1.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\"}]],[\"$\",\"$L3\",null,{\"buildId\":\"ujodldBbitf5aRemOarsS\",\"assetPrefix\":\"\",\"initialCanonicalUrl\":\"/_not-found\",\"initialTree\":[\"\",{\"children\":[\"/_not-found\",{\"children\":[\"__PAGE__\",{}]}]},\"$undefined\",\"$undefined\",true],\"initialSeedData\":[\"\",{\"children\":[\"/_not-found\",{\"children\":[\"__PAGE__\",{},[[\"$L4\",[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"},\"children\":\"404\"}],[\"$\",\"div\",null,{\"style\":{\"display\":\"inline-block\"},\"children\":[\"$\",\"h2\",null,{\"style\":{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0},\"children\":\"This page could not be found.\"}]}]]}]}]]],null],null]},[\"$\",\"$L5\",null,{\"parallelRouterKey\":\"children\",\"segmentPath\":[\"children\",\"/_not-found\",\"children\"],\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L6\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"notFoundStyles\":\"$undefined\",\"styles\":null}],null]},[[\"$\",\"html\",null,{\"lang\":\"en\",\"className\":\"__variable_f367f3\",\"children\":[\"$\",\"body\",null,{\"className\":\"relative min-h-screen bg-background text-slate-900\",\"children\":[[\"$\",\"div\",null,{\"className\":\"pointer-events-none absolute inset-x-0 top-0 -z-10 h-[420px] bg-gradient-to-b from-slate-100 via-white to-white\"}],[\"$\",\"div\",null,{\"className\":\"relative flex min-h-screen flex-col\",\"children\":[\"$\",\"$L5\",null,{\"parallelRouterKey\":\"children\",\"segmentPath\":[\"children\"],\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L6\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":\"$7\",\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":\"$8\",\"children\":\"404\"}],[\"$\",\"div\",null,{\"style\":\"$9\",\"children\":[\"$\",\"h2\",null,{\"style\":\"$a\",\"children\":\"This page could not be found.\"}]}]]}]}]],\"notFoundStyles\":[],\"styles\":null}]}]]}]}],null],null],\"couldBeIntercepted\":false,\"initialHead\":[[\"$\",\"meta\",null,{\"name\":\"robots\",\"content\":\"noindex\"}],\"$Lb\"],\"globalErrorComponent\":\"$c\",\"missingSlots\":\"$Wd\"}]]\n"])</script><script>self.__next_f.push([1,"b:[[\"$\",\"meta\",\"0\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}],[\"$\",\"meta\",\"1\",{\"charSet\":\"utf-8\"}],[\"$\",\"title\",\"2\",{\"children\":\"OWTF — Offensive Web Testing Framework\"}],[\"$\",\"meta\",\"3\",{\"name\":\"description\",\"content\":\"OWTF automates the uncreative part of web security testing so assessors can focus on insight, supporting OWASP, NIST, and PTES methodologies.\"}],[\"$\",\"meta\",\"4\",{\"name\":\"next-size-adjust\"}]]\n4:null\n"])</script></body></html>
---
layout: default
title: "404: This page could not be found."
description: "OWTF automates the uncreative part of web security testing so assessors can focus on insight, supporting OWASP, NIST, and PTES methodologies."
permalink: /404.html
noindex: true
---
<div class="pointer-events-none absolute inset-x-0 top-0 -z-10 h-[420px] bg-gradient-to-b from-slate-100 via-white to-white"></div>
<div class="relative flex min-h-screen flex-col">
{% include not-found.html %}
</div>
4 changes: 4 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
source "https://rubygems.org"

gem "github-pages", group: :jekyll_plugins
gem "webrick", "~> 1.8"
40 changes: 40 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# OWTF.github.io Website

This repository now uses a Jekyll source-first workflow for GitHub Pages.

## Local development

1. Install Ruby 3.2+ (see `.ruby-version`) and Bundler.
2. Install dependencies:
```bash
bundle install
```
3. Run locally:
```bash
bundle exec jekyll serve
```
4. Open `http://127.0.0.1:4000`.

## Build

```bash
bundle exec jekyll build
```

The generated output is written to `_site/` and should not be committed.

## Content parity note

The initial Jekyll migration preserves existing OWTF landing page content and formatting. Modernization changes should be made incrementally after parity sign-off.

## Passive scanner source

Passive scanner integration in this repository is pinned to upstream `owtf/online-passive-scanner`:

- https://github.com/owtf/online-passive-scanner

See `/docs/PASSIVE_SCANNER_SOURCE.md` for the integration contract.

The scanner is vendored at `/online-passive-scanner/` and is accessible at:

- `/online-passive-scanner/`
21 changes: 21 additions & 0 deletions _config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
title: "OWTF - Offensive Web Testing Framework"
description: "OWTF automates the uncreative part of web security testing so assessors can focus on insight, supporting OWASP, NIST, and PTES methodologies."
url: "https://owtf.github.io"
baseurl: ""
markdown: kramdown
plugins:
- jekyll-seo-tag
exclude:
- README.md
- Gemfile
- Gemfile.lock
- node_modules
- vendor
- vendor/bundle
- vendor/cache
- vendor/gems
- vendor/ruby
- .bundle
- .sass-cache
- .jekyll-cache
- .jekyll-metadata
10 changes: 10 additions & 0 deletions _includes/footer.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<footer class="section-container pb-16 text-sm text-slate-600"><div class="rounded-3xl border border-slate-200 bg-white px-8 py-10 shadow-card">
<div class="flex flex-col gap-6 md:flex-row md:items-center md:justify-between">
<div>
<p class="text-base font-semibold text-slate-900">OWTF</p>
<p class="mt-1 text-sm text-slate-600">Offensive Web Testing Framework &middot; An OWASP community project.</p>
</div>
<nav class="flex flex-wrap gap-4 text-slate-600"><a href="https://github.com/owtf/owtf" class="transition hover:text-slate-900">GitHub</a><a href="https://docs.owasp.org/projects/owtf/" class="transition hover:text-slate-900">Documentation</a><a href="https://owasp.org/www-project-owtf/" class="transition hover:text-slate-900">OWASP Project</a></nav>
</div>
<p class="mt-8 border-t border-slate-200 pt-6 text-xs text-slate-500">&copy; 2025 OWASP OWTF.</p>
</div></footer>
6 changes: 6 additions & 0 deletions _includes/header.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<header class="section-container pt-10"><nav class="flex items-center justify-between rounded-full border border-slate-200 bg-white/80 px-6 py-4 shadow-card backdrop-blur"><a class="flex items-center gap-3" href="/"><span class="flex h-10 w-10 items-center justify-center rounded-full border border-slate-200 bg-white text-sm font-semibold text-slate-900">OW</span><span class="hidden text-sm font-medium tracking-wide text-slate-600 sm:inline">Offensive Web Testing Framework</span></a><div class="hidden items-center gap-8 text-sm text-slate-600 md:flex">
<a href="#overview" class="transition hover:text-slate-900">Overview</a><a href="#capabilities" class="transition hover:text-slate-900">Capabilities</a><a href="#standards" class="transition hover:text-slate-900">Standards</a><a href="https://owtf.readthedocs.io/en/develop/" class="transition hover:text-slate-900">Docs</a>
</div>
<div class="flex items-center gap-3">
<a href="https://github.com/owtf/owtf" class="hidden rounded-full border border-slate-200 px-4 py-2 text-xs font-semibold text-slate-700 transition hover:border-slate-300 hover:text-slate-900 lg:inline-flex">View GitHub</a><a href="https://github.com/owtf/owtf/releases" class="inline-flex items-center gap-2 rounded-full bg-slate-900 px-4 py-2 text-xs font-semibold text-white transition hover:bg-slate-700">Get OWTF<span class="text-base leading-none">&rarr;</span></a>
</div></nav></header>
Loading