Skip to content
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
3bf1410
Docker files
dreadwitdastacc-IFA Dec 6, 2025
b6a2bdd
Create webpack.yml
dreadwitdastacc-IFA Dec 7, 2025
1fb179f
Bump the npm_and_yarn group across 1 directory with 11 updates
dependabot[bot] Dec 8, 2025
4561baf
chore(app): retire in-repo express shim (rely on @types/express)
dreadwitdastacc-IFA Dec 9, 2025
6a0e441
chore(app): retire in-repo express-validator shim (rely on @types/exp…
dreadwitdastacc-IFA Dec 9, 2025
cdb900d
chore(app): delete retired shims-express.d.ts
dreadwitdastacc-IFA Dec 9, 2025
7efce3d
chore(app): delete retired shims-express-validator.d.ts
dreadwitdastacc-IFA Dec 9, 2025
63182c0
Merge pull request #2 from dreadwitdastacc-IFA/fix/remove-inrepo-shims
dreadwitdastacc-IFA Dec 9, 2025
6a5cd9f
Merge branch 'main' into dependabot/npm_and_yarn/app/npm_and_yarn-eb6…
dreadwitdastacc-IFA Dec 9, 2025
39257a4
Merge pull request #1 from dreadwitdastacc-IFA/dependabot/npm_and_yar…
dreadwitdastacc-IFA Dec 9, 2025
00f0a45
ci: tighten CI (lint/test/integration); add husky+lint-staged; format…
dreadwitdastacc-IFA Dec 10, 2025
59c1d91
chore: stop tracking mongo-data and ignore husky directory
dreadwitdastacc-IFA Dec 10, 2025
6c28f0d
chore(test): add automerge test file
dreadwitdastacc-IFA Dec 11, 2025
49715d4
chore(rfc): propose web/mobile enhancements and add Dependabot config
dreadwitdastacc-IFA Dec 11, 2025
f9a82f2
Merge branch 'main' into enhance/web-mobile
dreadwitdastacc-IFA Dec 11, 2025
0decdfc
Merge pull request #5 from dreadwitdastacc-IFA/enhance/web-mobile
dreadwitdastacc-IFA Dec 11, 2025
73b60af
chore(deps): bump jake from 10.8.7 to 10.9.4 in /app
dependabot[bot] Dec 11, 2025
aff63f2
chore(deps): bump @types/node from 24.10.2 to 25.0.0 in /app
dependabot[bot] Dec 11, 2025
5bb96b9
chore(deps-dev): bump supertest from 6.3.4 to 7.1.4 in /app
dependabot[bot] Dec 11, 2025
0f4ebe1
chore(deps-dev): bump touch from 3.1.0 to 3.1.1 in /app
dependabot[bot] Dec 11, 2025
4b94ac9
Initial plan
Copilot Dec 12, 2025
230ca91
Fix corrupted CI workflow file - extract clean version
Copilot Dec 12, 2025
e81aea0
Add agent-debug job to capture results-agent.json
Copilot Dec 12, 2025
e8c0cd0
Add permissions block to agent-debug job for security
Copilot Dec 12, 2025
ca81aac
Merge pull request #11 from dreadwitdastacc-IFA/copilot/add-ci-debug-job
dreadwitdastacc-IFA Dec 12, 2025
caa4512
Merge pull request #6 from dreadwitdastacc-IFA/dependabot/npm_and_yar…
dreadwitdastacc-IFA Dec 12, 2025
fd42c1e
Merge pull request #7 from dreadwitdastacc-IFA/dependabot/npm_and_yar…
dreadwitdastacc-IFA Dec 12, 2025
f936d1a
Merge pull request #8 from dreadwitdastacc-IFA/dependabot/npm_and_yar…
dreadwitdastacc-IFA Dec 12, 2025
1d66e3d
Merge pull request #9 from dreadwitdastacc-IFA/dependabot/npm_and_yar…
dreadwitdastacc-IFA Dec 12, 2025
9f02363
Add CodeQL analysis workflow configuration
dreadwitdastacc-IFA Dec 14, 2025
ceee602
Update README.md
dreadwitdastacc-IFA Dec 26, 2025
2e9e711
Update app/package.json
dreadwitdastacc-IFA Dec 26, 2025
10e194b
Update app/models/Todo.js
dreadwitdastacc-IFA Dec 26, 2025
1daab53
Update app/views/todos.ejs
dreadwitdastacc-IFA Dec 26, 2025
02b63ce
Update app/routes/front.js
dreadwitdastacc-IFA Dec 26, 2025
719d6cc
Update .github/workflows/webpack.yml
dreadwitdastacc-IFA Dec 26, 2025
c656ad7
Apply suggestion from @Copilot
dreadwitdastacc-IFA Dec 26, 2025
51936e9
Apply suggestion from @Copilot
dreadwitdastacc-IFA Dec 26, 2025
df7d469
Apply suggestion from @Copilot
dreadwitdastacc-IFA Dec 26, 2025
6c9ee8e
Initial plan
Copilot Dec 28, 2025
358335a
Add clear completed tasks functionality
Copilot Dec 28, 2025
a5c1834
Implement multi-layer security and configure Husky
Copilot Dec 28, 2025
a434a68
Fix linting warning in server.js
Copilot Dec 28, 2025
46b652c
Fix validation inconsistencies and update documentation
Copilot Dec 28, 2025
69c6da8
Magnificently enhance CodeQL security analysis
Copilot Dec 28, 2025
d713ccf
Merge pull request #17 from dreadwitdastacc-IFA/copilot/merge-complet…
dreadwitdastacc-IFA Dec 28, 2025
f4f82e0
Initial plan
Copilot Dec 28, 2025
a011d52
test: mock todo model for offline runs
Copilot Dec 28, 2025
378c9b7
test: refine todo mock isolation
Copilot Dec 28, 2025
028e973
test: support filtering in todo mock
Copilot Dec 28, 2025
f01f7ab
Replace MongoMemoryServer tests with offline in-memory Todo mock
Copilot Dec 28, 2025
be47549
Merge pull request #18 from dreadwitdastacc-IFA/copilot/enhance-t-swe…
dreadwitdastacc-IFA Dec 28, 2025
649d387
Update SECURITY.md
dreadwitdastacc-IFA Jan 23, 2026
8c10a18
Update compose.yaml
dreadwitdastacc-IFA Jan 23, 2026
5c0f60e
Update README.md
dreadwitdastacc-IFA Jan 23, 2026
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
28 changes: 28 additions & 0 deletions .github/workflows/webpack.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: NodeJS with Webpack

on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]

jobs:
build:
runs-on: ubuntu-latest

strategy:
matrix:
node-version: [18.x, 20.x, 22.x]

steps:
- uses: actions/checkout@v4

- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}

- name: Build
Copy link

Copilot AI Dec 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The npm install command runs in the repository root, but package.json is located in the 'app/' subdirectory. This will fail because there's no package.json in the root. The workflow should change to the app directory before running npm install.

Suggested change
- name: Build
- name: Build
working-directory: app

Copilot uses AI. Check for mistakes.
run: |
npm install
npx webpack
Comment on lines +1 to +29
Copy link

Copilot AI Dec 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The workflow is named 'NodeJS with Webpack' but the repository doesn't use webpack - it's an Express/EJS application. Additionally, the build step runs 'npx webpack' which will fail since webpack is not configured or installed. This workflow appears to be copied from a template and not adapted for this project.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot open a new pull request to apply changes based on this feedback

10 changes: 7 additions & 3 deletions app/.dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
# https://docs.docker.com/engine/reference/builder/#dockerignore-file

**/.classpath
**/.dockerignore
**/.env
**/.git
**/.gitignore
Expand All @@ -30,5 +29,10 @@
**/values.dev.yaml
**/build
**/dist
LICENSE
README.md
logs/
*.log
coverage/
.DS_Store
Thumbs.db
*.swp
*.bak
5 changes: 4 additions & 1 deletion app/config/keys.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
// Enhanced configuration: supports environment-based MongoDB URIs for flexibility and security
const mongoProdURI = process.env.MONGO_PROD_URI || 'mongodb://todo-database:27017/todoapp';

module.exports = {
mongoProdURI: 'mongodb://todo-database:27017/todoapp',
mongoProdURI,
};
22 changes: 21 additions & 1 deletion app/models/Todo.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,27 @@ const Schema = mongoose.Schema;
const TodoSchema = new Schema({
task: {
type: String,
required: true
required: true,
minlength: 1,
maxlength: 100,
match: [/^[^<>]*$/, 'Task cannot contain < or > characters.']
},
completed: {
type: Boolean,
default: false,
index: true
},
priority: {
type: String,
enum: ['low', 'medium', 'high'],
default: 'medium'
},
due_date: {
type: Date
},
user: {
type: String,
default: 'unassigned'
},
created_at: {
type: Date,
Expand Down
19 changes: 19 additions & 0 deletions app/routes/front.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,24 @@ router.post('/todo/destroy', async (req, res) => {
res.redirect('/');
});

// POST - Edit todo item
router.post('/todo/edit', async (req, res) => {
const taskKey = req.body._key;
const newTask = req.body.task;
await Todo.findByIdAndUpdate(taskKey, { task: newTask });
res.redirect('/');
});

// POST - Toggle completion status
router.post('/todo/toggle', async (req, res) => {
const taskKey = req.body._key;
const todo = await Todo.findById(taskKey);
if (todo) {
todo.completed = !todo.completed;
await todo.save();
}
res.redirect('/');
});
Comment on lines +82 to +164
Copy link

Copilot AI Dec 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new /todo/edit and /todo/toggle endpoints lack input validation. If req.body._key is missing, undefined, or malformed, the routes will fail or behave unpredictably. Add validation to check that _key exists and is a valid MongoDB ObjectId before querying the database.

Copilot uses AI. Check for mistakes.


module.exports = router;
78 changes: 64 additions & 14 deletions app/views/todos.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -42,24 +42,39 @@
<div class="row">
<div class="col-12">
<% if(Object.keys(tasks).length> 0) { %>
<ul class="nav flex-column">
<ul class="nav flex-column" role="list" aria-label="Todo list">
<% tasks.forEach(todo=> { %>
<li class="nav-item">
<div class="d-flex justify-content-between py-1">
<div class="d-flex flex-row">
<div>
<%= todo.task %>
<p class="text-muted"><small>
<%= moment(todo.created_at).fromNow() %>
</small></p>
<li class="nav-item" role="listitem">
Copy link

Copilot AI Dec 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The attribute 'role="listitem"' is not a valid ARIA role. The correct role is "listitem" (one word), but more importantly, when using semantic HTML with a 'ul' element, the child 'li' elements already have an implicit role of listitem. This explicit role attribute is redundant and should be removed.

Suggested change
<li class="nav-item" role="listitem">
<li class="nav-item">

Copilot uses AI. Check for mistakes.
<div class="d-flex justify-content-between py-1 align-items-center" aria-live="polite">
<div class="d-flex flex-row align-items-center">
<form method="POST" action="/todo/toggle" aria-label="Toggle task completion">
<input type="hidden" name="_key" value="<%= todo._id %>" />
<input type="checkbox" name="completed" onchange="this.form.submit()" <%= todo.completed ? 'checked' : '' %> aria-label="Mark task as <%= todo.completed ? 'incomplete' : 'completed' %>">
Copy link

Copilot AI Dec 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The checkbox has 'onchange="this.form.submit()"' which will cause a traditional form submission and page reload. However, there's also an AJAX handler set up in the script section (lines 94-109) that's meant to handle the submission via AJAX. These two approaches conflict - the traditional form submit will execute before the AJAX handler can preventDefault. Remove the inline onchange attribute to let the AJAX handler manage the submission.

Suggested change
<input type="checkbox" name="completed" onchange="this.form.submit()" <%= todo.completed ? 'checked' : '' %> aria-label="Mark task as <%= todo.completed ? 'incomplete' : 'completed' %>">
<input type="checkbox" name="completed" <%= todo.completed ? 'checked' : '' %> aria-label="Mark task as <%= todo.completed ? 'incomplete' : 'completed' %>">

Copilot uses AI. Check for mistakes.
</form>
<div class="ml-2">
<span <%= todo.completed ? 'style="text-decoration: line-through; color: #888;"' : '' %>><%= todo.task %></span>
<p class="text-muted mb-0"><small>
<%= moment(todo.created_at).fromNow() %>
</small></p>
<span class="badge badge-<%= todo.completed ? 'success' : 'secondary' %> ml-1" aria-label="Task status">
<%= todo.completed ? 'Completed' : 'Pending' %>
</span>
</div>
</div>
<a href="javascript:;" onclick="this.children[0].submit()"
class="text-danger">
<form method="POST" action="/todo/destroy">
<a href="#" class="text-info mr-2" onclick="document.getElementById('edit-form-<%= todo._id %>').style.display='block';return false;" aria-label="Edit task">
Copy link

Copilot AI Dec 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The inline onclick handler 'onclick="document.getElementById('edit-form-<%= todo._id %>').style.display='block';return false;"' contains unescaped single quotes within the EJS template output, which will break the JavaScript string. The todo._id and 'block' values need proper escaping or the attribute should use double quotes with escaped inner quotes.

Suggested change
<a href="#" class="text-info mr-2" onclick="document.getElementById('edit-form-<%= todo._id %>').style.display='block';return false;" aria-label="Edit task">
<a href="#" class="text-info mr-2" onclick="document.getElementById(&quot;edit-form-<%= todo._id %>&quot;).style.display='block';return false;" aria-label="Edit task">

Copilot uses AI. Check for mistakes.
<i class="fa fa-pencil" aria-hidden="true"></i>
</a>
<form id="edit-form-<%= todo._id %>" method="POST" action="/todo/edit" style="display:none;" class="form-inline" aria-label="Edit task form">
<input type="hidden" name="_key" value="<%= todo._id %>" />
<input type="text" name="task" value="<%= todo.task %>" class="form-control form-control-sm mr-2" aria-label="Edit task input">
<button type="submit" class="btn btn-success btn-sm" aria-label="Save edit">Save</button>
<button type="button" class="btn btn-secondary btn-sm" onclick="this.parentElement.style.display='none';return false;" aria-label="Cancel edit">Cancel</button>
Copy link

Copilot AI Dec 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to line 64, this inline onclick handler has the same quote escaping issue. The JavaScript 'this.parentElement.style.display='none'' contains unescaped quotes that will break the attribute.

Suggested change
<button type="button" class="btn btn-secondary btn-sm" onclick="this.parentElement.style.display='none';return false;" aria-label="Cancel edit">Cancel</button>
<button type="button" class="btn btn-secondary btn-sm" onclick='this.parentElement.style.display="none";return false;' aria-label="Cancel edit">Cancel</button>

Copilot uses AI. Check for mistakes.
</form>
<a href="javascript:;" onclick="this.children[0].submit()" class="text-danger" aria-label="Delete task">
Copy link

Copilot AI Dec 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using 'href="javascript:;"' for the delete link is an outdated pattern. A better approach would be to use 'href="#"' with 'event.preventDefault()' in a proper click handler, or use a button element with type="button" which is more semantically correct for an action that doesn't navigate.

Suggested change
<a href="javascript:;" onclick="this.children[0].submit()" class="text-danger" aria-label="Delete task">
<a href="#" onclick="this.children[0].submit();return false;" class="text-danger" aria-label="Delete task">

Copilot uses AI. Check for mistakes.
<form method="POST" action="/todo/destroy" aria-label="Delete task form">
<input type="hidden" name="_key" value="<%= todo._id %>" />
</form>
<i class="fa fa-trash-o"></i>
<i class="fa fa-trash-o" aria-hidden="true"></i>
</a>
</div>
</li>
Expand All @@ -74,6 +89,41 @@
</div>
</div>
</div>
</body>
<script>
// AJAX for toggling completion
document.querySelectorAll('form[action="/todo/toggle"] input[type="checkbox"]').forEach(function(checkbox) {
checkbox.addEventListener('change', function(e) {
var form = this.form;
var xhr = new XMLHttpRequest();
xhr.open('POST', form.action, true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.onload = function() {
if (xhr.status === 200) {
location.reload(); // For simplicity, reload to reflect changes
}
};
var params = '_key=' + encodeURIComponent(form._key.value);
xhr.send(params);
e.preventDefault();
Comment thread
dreadwitdastacc-IFA marked this conversation as resolved.
Comment thread
dreadwitdastacc-IFA marked this conversation as resolved.
});
});

// AJAX for editing tasks
document.querySelectorAll('form[action="/todo/edit"]').forEach(function(editForm) {
editForm.addEventListener('submit', function(e) {
e.preventDefault();
var xhr = new XMLHttpRequest();
xhr.open('POST', editForm.action, true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.onload = function() {
if (xhr.status === 200) {
location.reload(); // For simplicity, reload to reflect changes
}
};
var params = '_key=' + encodeURIComponent(editForm._key.value) + '&task=' + encodeURIComponent(editForm.task.value);
xhr.send(params);
});
});
</script>
</body>
</html>