mirror of
https://github.com/hansjone/dsh-ops-cron.git
synced 2026-10-10 23:30:48 +08:00
Keep foreign cron cwd for super_admin via live role resolve and session default.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
9b8f937a65
commit
7a2a673ac2
9 changed files with 189 additions and 18 deletions
84
lib/host.js
84
lib/host.js
|
|
@ -30,6 +30,7 @@ import {
|
|||
claimUnassignedForViewer,
|
||||
filterJobsForIdentity,
|
||||
filterRunsForJobs,
|
||||
isElevatedCronRole,
|
||||
isMultiUserIdentity,
|
||||
localIdentity,
|
||||
migrateJobOwners,
|
||||
|
|
@ -175,6 +176,67 @@ async function requireIdentity(request, write, getUdsAuth) {
|
|||
return { ...identity, mode: 'multi', lang: identity.lang || locale }
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this identity / job owner may keep an explicit cwd outside the
|
||||
* provisioned tree. Re-resolves via uds-auth so stale tool identities (role
|
||||
* missing permissions, or Host with an older caller path) still work.
|
||||
*/
|
||||
function allowsForeignJobCwd(identity, getUdsAuth, ownerEmpNo) {
|
||||
if (canViewAllJobs(identity)) return true
|
||||
const uds = typeof getUdsAuth === 'function' ? getUdsAuth() : null
|
||||
const empNo = String(ownerEmpNo || identity?.empNo || '').trim()
|
||||
if (!empNo || empNo.startsWith('__') || !uds) return false
|
||||
if (typeof uds.resolveIdentityForEmpNo === 'function') {
|
||||
const live = uds.resolveIdentityForEmpNo(empNo)
|
||||
if (live && canViewAllJobs(live)) return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/** Merge live role/permissions onto a caller identity when uds-auth can look them up. */
|
||||
function enrichIdentity(identity, getUdsAuth) {
|
||||
if (!isMultiUserIdentity(identity)) return identity
|
||||
const uds = typeof getUdsAuth === 'function' ? getUdsAuth() : null
|
||||
if (typeof uds?.resolveIdentityForEmpNo === 'function') {
|
||||
const live = uds.resolveIdentityForEmpNo(identity.empNo)
|
||||
if (live?.empNo) {
|
||||
const canView = !!(
|
||||
live.permissions?.canViewAllSessions
|
||||
|| identity.permissions?.canViewAllSessions
|
||||
|| isElevatedCronRole(live.role)
|
||||
|| isElevatedCronRole(identity.role)
|
||||
)
|
||||
return {
|
||||
...identity,
|
||||
role: live.role || identity.role,
|
||||
displayName: live.displayName || identity.displayName || identity.empNo,
|
||||
permissions: {
|
||||
...(identity.permissions || {}),
|
||||
...(live.permissions || {}),
|
||||
canViewAllSessions: canView,
|
||||
canCreateWorkspace: !!(
|
||||
live.permissions?.canCreateWorkspace
|
||||
|| identity.permissions?.canCreateWorkspace
|
||||
|| canView
|
||||
),
|
||||
},
|
||||
workspacePath: live.workspacePath || identity.workspacePath || null,
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isElevatedCronRole(identity.role)) {
|
||||
return {
|
||||
...identity,
|
||||
permissions: {
|
||||
...(identity.permissions || {}),
|
||||
canViewAllSessions: true,
|
||||
canCreateWorkspace: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
return identity
|
||||
}
|
||||
|
||||
function sanitizeJobCwd(cwd, identity, getUdsAuth, { forOwnerEmpNo } = {}) {
|
||||
const raw = typeof cwd === 'string' ? cwd.trim() : ''
|
||||
const uds = typeof getUdsAuth === 'function' ? getUdsAuth() : null
|
||||
|
|
@ -183,7 +245,7 @@ function sanitizeJobCwd(cwd, identity, getUdsAuth, { forOwnerEmpNo } = {}) {
|
|||
? uds.getProvisionedWorkspacePath(owner)
|
||||
: null
|
||||
if (!raw) return ownerPath || ''
|
||||
if (canViewAllJobs(identity)) return raw
|
||||
if (allowsForeignJobCwd(identity, getUdsAuth, owner)) return raw
|
||||
// Without uds-auth, keep the caller cwd (tools may stamp owner from path only).
|
||||
if (!uds) return raw
|
||||
if (owner && uds?.isUserPath?.(owner, raw)) return raw
|
||||
|
|
@ -350,9 +412,12 @@ export function createHostService(options = {}) {
|
|||
safeInput.ownerDisplayName = ''
|
||||
// Keep cwd as the bot workspace path; do not sanitize via empNo.
|
||||
} else {
|
||||
const ownerIdentity = isMultiUserIdentity(identity)
|
||||
? identity
|
||||
: inferIdentityFromJobInput(safeInput, getUdsAuth)
|
||||
const ownerIdentity = enrichIdentity(
|
||||
isMultiUserIdentity(identity)
|
||||
? identity
|
||||
: inferIdentityFromJobInput(safeInput, getUdsAuth),
|
||||
getUdsAuth,
|
||||
)
|
||||
if (isMultiUserIdentity(ownerIdentity)) {
|
||||
const delivery = normalizeDelivery(safeInput.delivery || { kind: 'dsh' })
|
||||
assertDeliveryAllowedForIdentity(delivery, ownerIdentity)
|
||||
|
|
@ -412,18 +477,19 @@ export function createHostService(options = {}) {
|
|||
ownerDisplayName: job.ownerDisplayName || '',
|
||||
}
|
||||
if (patch._identity) {
|
||||
const enriched = enrichIdentity(patch._identity, getUdsAuth)
|
||||
if (patch.delivery !== undefined) {
|
||||
nextInput.delivery = mergeDeliveryMention(job.delivery, patch.delivery)
|
||||
assertDeliveryAllowedForIdentity(nextInput.delivery, patch._identity)
|
||||
assertDeliveryAllowedForIdentity(nextInput.delivery, enriched)
|
||||
}
|
||||
nextInput.cwd = sanitizeJobCwd(
|
||||
nextInput.cwd,
|
||||
patch._identity,
|
||||
enriched,
|
||||
getUdsAuth,
|
||||
{ forOwnerEmpNo: nextInput.ownerEmpNo },
|
||||
)
|
||||
}
|
||||
if (patch.ownerEmpNo !== undefined && canViewAllJobs(patch._identity)) {
|
||||
if (patch.ownerEmpNo !== undefined && canViewAllJobs(enrichIdentity(patch._identity, getUdsAuth))) {
|
||||
nextInput.ownerEmpNo = normalizeOwnerEmpNo(patch.ownerEmpNo)
|
||||
if (patch.ownerDisplayName !== undefined) {
|
||||
nextInput.ownerDisplayName = String(patch.ownerDisplayName || '').trim().slice(0, 80)
|
||||
|
|
@ -1004,16 +1070,18 @@ function sessionCwdOf(ctx, sessionId) {
|
|||
|
||||
/**
|
||||
* True when the job owner may keep an explicit cwd outside their provisioned tree
|
||||
* (super_admin / fallback_admin via canViewAllSessions or canCreateWorkspace).
|
||||
* (super_admin / fallback_admin via canViewAllSessions, canCreateWorkspace, or role).
|
||||
*/
|
||||
export function ownerAllowsForeignCwd(ownerEmpNo, uds) {
|
||||
const empNo = String(ownerEmpNo || '').trim()
|
||||
if (!empNo || empNo.startsWith('__') || !uds) return false
|
||||
if (typeof uds.resolveIdentityForEmpNo === 'function') {
|
||||
const identity = uds.resolveIdentityForEmpNo(empNo)
|
||||
if (canViewAllJobs(identity)) return true
|
||||
return !!(
|
||||
identity?.permissions?.canViewAllSessions
|
||||
|| identity?.permissions?.canCreateWorkspace
|
||||
|| isElevatedCronRole(identity?.role)
|
||||
)
|
||||
}
|
||||
return false
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue