@goodandready/dsh-github-ops 0.6.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/routes.js CHANGED
@@ -12,6 +12,7 @@ import { statusPayload, isTrustedRequest, isTrustedWriteRequest, sendJson } from
12
12
  import { buildAction, validateCwd, validateStashRef, resolveConflictFile } from './scm-write.js'
13
13
  import { parseStatus, parseBranches, parseStashes, parseWorktrees, parseCount, scmPayload, mergeStateFrom, hasConflicts, parseConflictBlocks, parseDiffHunks, parseGitGraph } from './scm.js'
14
14
  import { SseEventManager } from './events.js'
15
+ import { encodeRepoPath } from './github.js'
15
16
  import { listIssues } from './tools/issues.js'
16
17
  import { listRuns } from './tools/actions.js'
17
18
  import { listNotifications, repoTreeView } from './tools/panel-data.js'
package/lib/scm-write.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { realpathSync, existsSync, readFileSync, writeFileSync } from 'node:fs'
2
- import { join as joinPath } from 'node:path'
2
+ import { join as joinPath, posix, win32 } from 'node:path'
3
3
  import { hasConflicts, resolveConflictContent } from './scm.js'
4
4
  // Writing to a working copy, from the Source Control tab.
5
5
  //
@@ -206,29 +206,47 @@ export const OPERATION_VERBS = Object.freeze(CONTINUE_VERBS.slice())
206
206
  */
207
207
  const DISALLOWED_ROOTS = ['/etc', '/proc', '/sys', '/dev', '/root', '/bin', '/sbin', '/usr', '/boot', '/var/run']
208
208
 
209
+ function checkDisallowed(p) {
210
+ const norm = p.replace(/\\/g, '/')
211
+ for (const root of DISALLOWED_ROOTS) {
212
+ if (norm === root || norm.startsWith(root + '/')) {
213
+ throw new Error(`access to system directory "${root}" is not allowed`)
214
+ }
215
+ }
216
+ const driveMatch = norm.match(/^[a-zA-Z]:(\/.*)?$/)
217
+ if (driveMatch) {
218
+ const sub = (driveMatch[1] || '/').toLowerCase()
219
+ if (sub === '/' || sub === '') {
220
+ throw new Error('access to system drive root is not allowed')
221
+ }
222
+ for (const winDir of ['/windows', '/winnt', '/system32', '/boot']) {
223
+ if (sub === winDir || sub.startsWith(winDir + '/')) {
224
+ throw new Error(`access to system directory "${winDir.slice(1)}" is not allowed`)
225
+ }
226
+ }
227
+ }
228
+ }
229
+
209
230
  export function validateCwd(path) {
210
231
  const value = String(path == null ? '' : path).trim()
211
232
  if (!value) return ''
212
- if (!value.startsWith('/')) throw new Error('a repository path must be absolute')
233
+ if (!posix.isAbsolute(value) && !win32.isAbsolute(value)) {
234
+ throw new Error('a repository path must be absolute')
235
+ }
213
236
  if (value.includes('..')) throw new Error('a repository path may not contain ".."')
214
237
  if (/[\x00-\x1f]/.test(value)) throw new Error('a repository path may not contain control characters')
215
238
  if (value.length > 500) throw new Error('a repository path is too long')
216
- for (const root of DISALLOWED_ROOTS) {
217
- if (value === root || value.startsWith(root + '/')) {
218
- throw new Error(`access to system directory "${root}" is not allowed`)
219
- }
220
- }
239
+
240
+ checkDisallowed(value)
241
+
221
242
  let realPath = value
222
243
  try {
223
244
  realPath = realpathSync(value)
224
245
  } catch {
225
246
  realPath = value
226
247
  }
227
- for (const root of DISALLOWED_ROOTS) {
228
- if (realPath === root || realPath.startsWith(root + '/')) {
229
- throw new Error(`access to system directory "${root}" is not allowed`)
230
- }
231
- }
248
+ checkDisallowed(realPath)
249
+
232
250
  return value
233
251
  }
234
252
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@goodandready/dsh-github-ops",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "description": "GitHub operations for DeepSeek Harness: releases, tags, a guarded generic API pass-through, workflow runs, secrets and sanitized mirror publication.",
5
5
  "license": "MIT",
6
6
  "type": "module",