Skip to content
Open
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
198 changes: 198 additions & 0 deletions .agents/skills/release-notes/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
---
name: release-notes
description: Draft release notes for the next FACTION release by reading commit diffs since the previous tag and pushing them to GitHub as a DRAFT release via `gh release create --draft` (or updating an existing draft). Use when the user asks to draft/prepare release notes, summarize what's changed since a tag, or prepare a release writeup. Never publishes — always draft.
---

# FACTION release notes

You are drafting human-quality release notes for the FACTION project. The goal
is the kind of writeup a user reads in a GitHub Release and immediately
understands what changed, why it matters to them, and whether they need to
do anything to upgrade.

Keyword-matching commit subjects produces shallow output. **Read the diffs.**
That is the difference between "Add default-vulnerability CRUD endpoints" (a
commit subject) and a release-notes paragraph that lists each new endpoint,
its method/path, and the round-trip-cleanly fix for names containing `/`.

## Step 1 — Pick the version

If the user passed a version (e.g. `/release-notes 1.8.6`), use it.

Otherwise derive it from `pom.xml`:

```bash
grep -m1 '<version>' pom.xml | sed -E 's/.*<version>([^<]+)<\/version>.*/\1/' | sed 's/-SNAPSHOT//'
```

If the result still contains `SNAPSHOT` or is empty, stop and ask the user
which version this release should be tagged as.

## Step 2 — Pick the previous tag

Default to the most recent annotated/lightweight tag:

```bash
git describe --tags --abbrev=0
```

If that errors (no tags exist), ask the user for a starting ref instead of
guessing. If the user passed a second arg, use that as the previous tag.

## Step 3 — Inspect what changed

Run these (in parallel where independent):

```bash
git log --reverse <prev-tag>..HEAD --pretty=format:'%h %s'
git diff --stat <prev-tag>..HEAD
```

Then **for each non-trivial commit**, read the actual diff:

```bash
git show --stat <sha>
git show <sha> -- <interesting paths>
```

Skip commits whose subject starts with `[maven-release-plugin]` — they are
version-bump noise. Also skip pure-internal hygiene (gitignore tweaks,
formatting-only changes) unless that's all that landed.

If `.github/release.yml` exists, read it — its `categories` section names
match the GitHub Release auto-categorizer (currently
`🎉 🚀 Upgrades 🎉 🚀` and `🐛 Bugfixes 🐛`). Use those exact section
titles so the file mirrors what GitHub would generate.

## Step 4 — Draft on GitHub

You will push a draft release to GitHub rather than committing a markdown
file to the repo. The user reviews and publishes from
<https://github.com/factionsecurity/faction/releases>.

Preflight:

```bash
gh auth status # verify gh is installed and logged in
gh release view <version> # check if a release for this version already exists
```

- If `gh auth status` fails, stop and tell the user to run `gh auth login`.
- If `gh release view` succeeds **and** the release is published (not a
draft), stop and ask before overwriting — published releases should not be
silently mutated.
- If `gh release view` succeeds and the release **is** a draft, you'll
update it in place via `gh release edit` (see below).
- If `gh release view` fails with "release not found", you'll create a new
draft via `gh release create`.

Compose the notes body using the structure below, then write it to a temp
file (`/tmp/release-notes-<version>.md`) — passing markdown via `--notes`
inline is fragile with backticks and code fences, so always use
`--notes-file`.

Body structure (omit any section that's empty):

The body starts directly with the executive summary — do **not** add a
`# FACTION <version>` title or a `_Release date: ..._` line. GitHub already
renders the release title and date from the release object itself.

```markdown
<One-paragraph executive summary — what's the headline of this release?
Mention the 2-3 biggest things in plain language. No bullet list here.>

## 🎉 🚀 Upgrades 🎉 🚀

### <Feature name>

<Prose explanation: what is it, why does it exist, what can a user now do
that they couldn't before? For API additions, include a method/path table.
For format changes, include a short example. Note backward-compat behavior
explicitly.>

## 🐛 Bugfixes 🐛

- <One bullet per fix. Lead with the user-visible symptom, then the cause
in parens. "X was broken when Y; root cause was Z" beats "Fix Z".>

## 🧰 Internal / Test infrastructure

<Only include if there are notable test or build changes that matter to
contributors. Skip if the only internal change is a typo fix.>

## Upgrade notes

- **Database migration:** required / not required (state which).
- **API:** call out any breaking changes, or explicitly say "all existing
endpoints continue to work unchanged" if true.
- **Configuration:** any new required env vars or settings.
- **Permissions:** any new permission scopes or role changes.

## Full changelog

<https://github.com/factionsecurity/faction/compare/<prev-tag>...<version>>
```

## Style rules

- **Read diffs, don't paraphrase commit subjects.** A commit titled "fix bug"
tells the reader nothing; the diff tells you what actually changed.
- **User-facing voice.** "You can now …" beats "We added a method that …".
- **Group by feature, not by commit.** Three commits that together
implement one endpoint become one bullet.
- **Tables for API additions.** Method / path / purpose. Always.
- **Backward compatibility is load-bearing.** If old clients keep working,
say so explicitly — that's often the most reassuring sentence in the file.
- **No emojis inside body text.** They're fine in the section headers
(because `.github/release.yml` uses them), but don't sprinkle them through
the prose.
- **No "Co-Authored-By" anywhere.** This project's commits and release
notes never carry that trailer.

## Step 5 — Push the draft

Write the composed body to the temp file, then create or update the draft.

**New draft** (no existing release for `<version>`):

```bash
gh release create <version> \
--draft \
--title "FACTION <version>" \
--notes-file /tmp/release-notes-<version>.md \
--target main
```

`--draft` is mandatory — never publish from this skill. The tag does not
have to exist yet; GitHub creates it at `--target` only when the draft is
published.

**Existing draft** (re-running the skill to iterate on the same release):

```bash
gh release edit <version> \
--draft \
--notes-file /tmp/release-notes-<version>.md
```

`gh release edit` keeps the existing title unless `--title` is also passed.
Only pass `--title` if the user explicitly asked to rename the release.

## Hand-off

After the `gh` command succeeds:
1. Print the draft URL. `gh release create` prints it on stdout; for the
edit path, get it with `gh release view <version> --json url -q .url`.
2. Print the first ~10 lines of the body so the user can sanity-check the
framing without leaving the terminal.
3. Tell the user the draft is **unpublished** and that they should review
on GitHub before clicking Publish.
4. Do **not** publish, `git tag`, or `git push` anything. The skill's
contract ends at "draft is up for review."

## When gh isn't available

If `gh` is not installed or the user is offline, fall back to writing
`RELEASE_NOTES_<version>.md` at the repo root and tell the user explicitly
that you did so because GitHub was unreachable — they can paste it into
the Releases UI manually.
7 changes: 7 additions & 0 deletions .codex/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[mcp_servers.faction]
command = "node"
args = ["/Volumes/extended/Code/faction-all/free/faction-mcp/dist/index.js"]

[mcp_servers.faction.env]
FACTION_API_KEY = "bf9bff1a-fc5d-4e86-adc3-86bb9165d180"
FACTION_BASE_URL = "https://acme.factionsecurity.com"
3 changes: 2 additions & 1 deletion WebContent/WEB-INF/jsp/assessment/list.jsp
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,8 @@ color:#00a65a

<script src="../dist/js/listbootstrap.js"></script>
<!--
<script src="../plugins/jQuery/jQuery-2.1.4.min.js"></script> -->
<script src="../plugins/jQuery/jquery-3.7.1.min.js"></script>
<script src="../plugins/jQuery/jquery-migrate-3.6.0.min.js"></script> -->
<script src="../plugins/iCheck/icheck.min.js"></script>
<!-- DataTables -->
<script src="../plugins/datatables/jquery.dataTables.min.js"></script>
Expand Down
5 changes: 3 additions & 2 deletions WebContent/WEB-INF/jsp/client/Access.jsp
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,9 @@
</footer>
</div>

<!-- jQuery 2.1.4 -->
<script src="../plugins/jQuery/jQuery-2.1.4.min.js"></script>
<!-- jQuery 3.7.1 (+ migrate shim for legacy plugins) -->
<script src="../plugins/jQuery/jquery-3.7.1.min.js"></script>
<script src="../plugins/jQuery/jquery-migrate-3.6.0.min.js"></script>
<!-- Bootstrap 3.3.5 -->
<script src="../bootstrap/js/bootstrap.min.js"></script>
<script src="../dist/js/app.js"></script>
Expand Down
5 changes: 3 additions & 2 deletions WebContent/WEB-INF/jsp/client/Client.jsp
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,9 @@
</footer>
</div>

<!-- jQuery 2.1.4 -->
<script src="../plugins/jQuery/jQuery-2.1.4.min.js"></script>
<!-- jQuery 3.7.1 (+ migrate shim for legacy plugins) -->
<script src="../plugins/jQuery/jquery-3.7.1.min.js"></script>
<script src="../plugins/jQuery/jquery-migrate-3.6.0.min.js"></script>
<!-- Bootstrap 3.3.5 -->
<script src="../bootstrap/js/bootstrap.min.js"></script>
<script src="../dist/js/app.js"></script>
Expand Down
2 changes: 1 addition & 1 deletion WebContent/WEB-INF/jsp/cms/ReportingTemplates.jsp
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@
<bs:row>
<bs:select name="Assessment Type" colsize="6" id="asmtType">
<s:iterator value="types">
<option value="${id }">${type }</option>
<option value="${id }"><s:property value="type"/></option>
</s:iterator>
</bs:select>
<bs:select name="Assessment Team" colsize="6" id="asmtTeam">
Expand Down
4 changes: 2 additions & 2 deletions WebContent/WEB-INF/jsp/cms/TemplateUpload.jsp
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,10 @@
<bs:select name="Assessment Type" colsize="12" id="type">
<s:iterator value="types">
<s:if test="selectedTemplate.type.id == id">
<option value="${id }" selected="selected">${type}</option>
<option value="${id }" selected="selected"><s:property value="type"/></option>
</s:if>
<s:else>
<option value="${id }">${type}</option>
<option value="${id }"><s:property value="type"/></option>

</s:else>
</s:iterator>
Expand Down
2 changes: 1 addition & 1 deletion WebContent/WEB-INF/jsp/cms/templates.jsp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ height: 700px;
<bs:mco colsize="12">
<<bs:datatable columns="Template Name,Team" classname="" id="" >
<s:iterator var="reports">
<tr id="rpt_${id }"><td>${name }</td><td>${team.teamName}</td></tr>
<tr id="rpt_${id }"><td><s:property value="name"/></td><td><s:property value="team.teamName"/></td></tr>
</s:iterator>
</bs:datatable>
</bs:mco>
Expand Down
7 changes: 4 additions & 3 deletions WebContent/WEB-INF/jsp/header.jsp
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@
<link rel="stylesheet" href="../plugins/loading/css/jquery-loading.css">
<link rel="stylesheet" href="../dist/css/Fuse.css">

<!-- jQuery 2.1.4 -->
<script src="../plugins/jQuery/jQuery-2.1.4.min.js"></script>
<!-- jQuery 3.7.1 (+ migrate shim for legacy plugins) -->
<script src="../plugins/jQuery/jquery-3.7.1.min.js"></script>
<script src="../plugins/jQuery/jquery-migrate-3.6.0.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.9.2/dist/umd/popper.min.js"></script>
<script src="../dist/js/fuse.js"></script>
<script src="../dist/js/main.js"></script>
Expand Down Expand Up @@ -57,7 +58,7 @@
<span class="logo-mini"><img class="icon-img" src="../tri-logo.png" /></span>
<!-- logo for regular state and mobile devices -->
<span class="logo-lg"><img class="icon-img"
src="../tri-logo.png" />&nbsp;&nbsp;<b>${_title1}</b> ${_title2}</span>
src="../tri-logo.png" />&nbsp;&nbsp;<b><s:property value="_title1"/></b> <s:property value="_title2"/></span>
</a>

<!-- Header Navbar -->
Expand Down
14 changes: 7 additions & 7 deletions WebContent/WEB-INF/jsp/peerreviews/TrackChanges.jsp
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ span.Informational {
<!-- Content Header (Page header) -->
<section class="content-header">
<h1>
<i class="glyphicon glyphicon-eye-open"></i> Peer Review for <b>[${asmt.appId}] - ${asmt.name }</b> - <i>${asmt.assessor[0].fname} ${asmt.assessor[0].lname}</i>
<i class="glyphicon glyphicon-eye-open"></i> Peer Review for <b>[<s:property value="asmt.appId"/>] - <s:property value="asmt.name"/></b> - <i><s:property value="asmt.assessor[0].fname"/> <s:property value="asmt.assessor[0].lname"/></i>
<small></small>
</h1>
</section>
Expand Down Expand Up @@ -168,7 +168,7 @@ span.Informational {
<bs:row>
<bs:mco colsize="7">
<div class="text-header" id="summary_header"></div>
<textarea id="appsum" style="width: 100%" ><s:property value="replaceNewline(asmt.summary)" escapeHtml="false"/></textarea>
<textarea id="appsum" style="width: 100%" ><s:property value="replaceNewline(asmt.summary)"/></textarea>
</bs:mco>
<bs:mco colsize="4">
<div class="text-header">Notes <span id="summary_notes_header"></span></div>
Expand All @@ -189,7 +189,7 @@ span.Informational {
<bs:row>
<bs:mco colsize="7">
<div class="text-header" id="risk_header"></div>
<textarea id="risk" style="width: 100%" <s:if test="!showComplete">readOnly</s:if>><s:property value="replaceNewline(asmt.riskAnalysis)" escapeHtml="false"/></textarea>
<textarea id="risk" style="width: 100%" <s:if test="!showComplete">readOnly</s:if>><s:property value="replaceNewline(asmt.riskAnalysis)"/></textarea>
</bs:mco>
<bs:mco colsize="4">
<div class="text-header">Notes <span id="risk_notes_header"></span></div>
Expand Down Expand Up @@ -260,7 +260,7 @@ span.Informational {

<bs:mco colsize="7">
<div class="text-header" >Description <span id="vuln_desc['${id}']_header"></span></div>
<textarea id="vuln_desc['${id}']" style="width: 100%" <s:if test="!showComplete">readOnly</s:if>><s:property value="replaceNewline(description)" escapeHtml="false"/></textarea>
<textarea id="vuln_desc['${id}']" style="width: 100%" <s:if test="!showComplete">readOnly</s:if>><s:property value="replaceNewline(description)"/></textarea>
</bs:mco>
<bs:mco colsize="4">
<div class="text-header" >Description Notes <span id="vuln_desc_notes['${id}']_header"></span></div>
Expand All @@ -276,7 +276,7 @@ span.Informational {
<bs:row>
<bs:mco colsize="7">
<div class="text-header" >Recommendation <span id="vuln_rec['${id}']_header"></span></div>
<textarea id="vuln_rec['${id}']" style="width: 100%" <s:if test="!showComplete">readOnly</s:if>><s:property value="replaceNewline(recommendation)" escapeHtml="false"/></textarea>
<textarea id="vuln_rec['${id}']" style="width: 100%" <s:if test="!showComplete">readOnly</s:if>><s:property value="replaceNewline(recommendation)"/></textarea>
</bs:mco>
<bs:mco colsize="4">
<div class="text-header">Recommendation Notes <span id="vuln_rec_notes['${id}']_header"></span></div>
Expand All @@ -292,7 +292,7 @@ span.Informational {
<bs:row>
<bs:mco colsize="7">
<div class="text-header" >Details <span id="vuln_details['${id}']_header"></span></div>
<textarea id="vuln_details['${id}']" style="width: 100%" <s:if test="!showComplete">readOnly</s:if>><s:property value="replaceNewline(details)" escapeHtml="false"/></textarea>
<textarea id="vuln_details['${id}']" style="width: 100%" <s:if test="!showComplete">readOnly</s:if>><s:property value="replaceNewline(details)"/></textarea>
</bs:mco>
<bs:mco colsize="4">
<div class="text-header">Detail Notes <span id="vuln_detail_notes['${id}']_header"></span></div>
Expand Down Expand Up @@ -375,7 +375,7 @@ span.Informational {
</s:else>

</td>
<td><textarea class="form-control" style="width:100%" id="tx${id }" readonly>${notes}</textarea></td>
<td><textarea class="form-control" style="width:100%" id="tx${id }" readonly><s:property value="notes"/></textarea></td>
<td>
<s:if test="answer.value == 0">
Incomplete
Expand Down
4 changes: 3 additions & 1 deletion WebContent/WEB-INF/jsp/register/newuser.jsp
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,9 @@
</h4>
User Name and/or Password is invalid
</div>
<script src="plugins/jQuery/jQuery-2.1.4.min.js"
<script src="plugins/jQuery/jquery-3.7.1.min.js"
type="text/javascript"></script>
<script src="plugins/jQuery/jquery-migrate-3.6.0.min.js"
type="text/javascript"></script>
<script type="text/javascript">
$(function() {
Expand Down
4 changes: 3 additions & 1 deletion WebContent/WEB-INF/jsp/register/reset.jsp
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,9 @@
</h4>
<s:property value="message" />
</div>
<script src="plugins/jQuery/jQuery-2.1.4.min.js"
<script src="plugins/jQuery/jquery-3.7.1.min.js"
type="text/javascript"></script>
<script src="plugins/jQuery/jquery-migrate-3.6.0.min.js"
type="text/javascript"></script>
<script type="text/javascript">
$(function() {
Expand Down
Loading
Loading