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
36 changes: 0 additions & 36 deletions rules/001_project_settings/001_0007_hash_algorithm_test.rego

This file was deleted.

25 changes: 25 additions & 0 deletions rules/001_project_settings/001_0007_hash_algorithm_test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
TestCases:
- name: allow BCrypt hash algorithm
allow: true
input:
Settings:
$Type: Settings$ModelSettings
HashAlgorithm: BCrypt
- name: allow SSHA256 hash algorithm
allow: true
input:
Settings:
$Type: Settings$ModelSettings
HashAlgorithm: SSHA256
- name: do not allow SHA256 hash algorithm
allow: false
input:
Settings:
$Type: Settings$ModelSettings
HashAlgorithm: SHA256
- name: do not allow MD5 hash algorithm
allow: false
input:
Settings:
$Type: Settings$ModelSettings
HashAlgorithm: MD5

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
TestCases:
- name: allow when user role is checked for security
allow: true
input:
UserRoles:
- $Type: Security$UserRole
Name: Administrator
CheckSecurity: true
- name: do not allow when user role is not checked for security
allow: false
input:
UserRoles:
- $Type: Security$UserRole
Name: Administrator
CheckSecurity: false
Original file line number Diff line number Diff line change
@@ -1,28 +1,26 @@
# The rule reads Security$ProjectSecurity.yaml from the working directory.
# During tests the working directory is this rule's folder, which contains a
# fixture Security$ProjectSecurity.yaml with StrictMode disabled. Cases that
# enable the optimized (React) client therefore expect a violation.
TestCases:
- name: allow when UseOptimizedClient is false
- name: allow when optimized client is disabled
allow: true
input:
UseOptimizedClient: false
files:
"Security$ProjectSecurity.yaml":
StrictMode: false
- name: allow when both UseOptimizedClient and StrictMode are true
$Type: Settings$ProjectSettings
Settings:
- $Type: Forms$WebUIProjectSettingsPart
UseOptimizedClient: "No"
- name: allow when optimized client setting is absent
allow: true
input:
UseOptimizedClient: true
files:
"Security$ProjectSecurity.yaml":
StrictMode: true
- name: do not allow UseOptimizedClient true but StrictMode false
$Type: Settings$ProjectSettings
Settings:
- $Type: Settings$ModelSettings
HashAlgorithm: BCrypt
- name: do not allow optimized client enabled while strict mode is disabled
allow: false
input:
UseOptimizedClient: true
files:
"Security$ProjectSecurity.yaml":
StrictMode: false
- name: do not allow UseOptimizedClient true but StrictMode missing
allow: false
input:
UseOptimizedClient: true
files:
"Security$ProjectSecurity.yaml": {}
$Type: Settings$ProjectSettings
Settings:
- $Type: Forms$WebUIProjectSettingsPart
UseOptimizedClient: "Yes"
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# METADATA
# scope: package
# title: Security level should be set to production
# description: The project security level should be "CheckEverything" so that both page and microflow access as well as entity access are enforced. Lower levels leave parts of the app unprotected.
# authors:
# - Xiwen Cheng <x@cinaq.com>
# related_resources:
# - https://sdf-docs.clevr.com/?docs=acr-rules/security/securitylevel
# custom:
# category: Security
# rulename: SecurityLevelCheckEverything
# severity: HIGH
# rulenumber: "001_0010"
# remediation: Set the security level to "CheckEverything" in the project security settings.
# input: .*Security\$ProjectSecurity\.yaml
package app.mendix.project_settings.security_level_check_everything

import rego.v1

annotation := rego.metadata.chain()[1].annotations

default allow := false

allow if count(errors) == 0

errors contains error if {
input.SecurityLevel != "CheckEverything"

error := sprintf(
"[%v, %v, %v] Security level is %v, expected CheckEverything",
[
annotation.custom.severity,
annotation.custom.category,
annotation.custom.rulenumber,
input.SecurityLevel,
],
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
TestCases:
- name: allow CheckEverything
allow: true
input:
$Type: Security$ProjectSecurity
SecurityLevel: CheckEverything
- name: do not allow CheckNothing
allow: false
input:
$Type: Security$ProjectSecurity
SecurityLevel: CheckNothing
- name: do not allow CheckSecurity
allow: false
input:
$Type: Security$ProjectSecurity
SecurityLevel: CheckSecurity
37 changes: 37 additions & 0 deletions rules/001_project_settings/001_0011_strict_page_url_check.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# METADATA
# scope: package
# title: Strict page URL check should be enabled
# description: With strict page URL check enabled, pages can only be opened through a valid navigation path, which prevents users from reaching pages they should not have direct access to.
# authors:
# - Xiwen Cheng <x@cinaq.com>
# related_resources:
# - https://sdf-docs.clevr.com/?docs=acr-rules/security/securitystrictpageurl
# custom:
# category: Security
# rulename: StrictPageUrlCheck
# severity: MEDIUM
# rulenumber: "001_0011"
# remediation: Enable "Strict page URL check" in the project security settings.
# input: .*Security\$ProjectSecurity\.yaml
package app.mendix.project_settings.strict_page_url_check

import rego.v1

annotation := rego.metadata.chain()[1].annotations

default allow := false

allow if count(errors) == 0

errors contains error if {
input.StrictPageUrlCheck == false

error := sprintf(
"[%v, %v, %v] Strict page URL check is disabled",
[
annotation.custom.severity,
annotation.custom.category,
annotation.custom.rulenumber,
],
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
TestCases:
- name: allow when strict page url check enabled
allow: true
input:
$Type: Security$ProjectSecurity
StrictPageUrlCheck: true
- name: do not allow when strict page url check disabled
allow: false
input:
$Type: Security$ProjectSecurity
StrictPageUrlCheck: false
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# METADATA
# scope: package
# title: Allow only one session per user
# description: Allowing multiple concurrent sessions per user increases the attack surface and makes it harder to invalidate a session. Restrict users to a single active session unless there is a clear business reason.
# authors:
# - Xiwen Cheng <x@cinaq.com>
# related_resources:
# - https://sdf-docs.clevr.com/?docs=acr-rules/security/securityallowonesessionperuser
# custom:
# category: Security
# rulename: AllowOneSessionPerUser
# severity: MEDIUM
# rulenumber: "001_0012"
# remediation: Disable "Allow multiple sessions per user" in the project runtime settings.
# input: .*Settings\$ProjectSettings\.yaml
package app.mendix.project_settings.allow_one_session_per_user

import rego.v1

annotation := rego.metadata.chain()[1].annotations

default allow := false

allow if count(errors) == 0

errors contains error if {
some part in input.Settings
part["$Type"] == "Settings$ModelSettings"
part.AllowUserMultipleSessions == true

error := sprintf(
"[%v, %v, %v] Multiple sessions per user are allowed",
[
annotation.custom.severity,
annotation.custom.category,
annotation.custom.rulenumber,
],
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
TestCases:
- name: allow single session per user
allow: true
input:
$Type: Settings$ProjectSettings
Settings:
- $Type: Settings$ModelSettings
AllowUserMultipleSessions: false
HashAlgorithm: BCrypt
- name: do not allow multiple sessions per user
allow: false
input:
$Type: Settings$ProjectSettings
Settings:
- $Type: Settings$ModelSettings
AllowUserMultipleSessions: true
HashAlgorithm: BCrypt
- name: allow when other settings parts present but model settings ok
allow: true
input:
$Type: Settings$ProjectSettings
Settings:
- $Type: Forms$WebUIProjectSettingsPart
UseOptimizedClient: "No"
- $Type: Settings$ModelSettings
AllowUserMultipleSessions: false
67 changes: 67 additions & 0 deletions rules/001_project_settings/001_0013_unassigned_module_role.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
const metadata = {
scope: "package",
title: "Module roles should be assigned to a user role",
description: "A module role that is not connected to any user role can never be granted to a user. It is usually a leftover or a modeling mistake and should be assigned or removed.",
authors: ["Xiwen Cheng <x@cinaq.com>"],
related_resources: ["https://sdf-docs.clevr.com/?docs=acr-rules/reliability/unassignedmodulerole"],
custom: {
category: "Reliability",
rulename: "UnassignedModuleRole",
severity: "LOW",
rulenumber: "001_0013",
remediation: "Assign the module role to at least one user role, or remove it from the module security.",
input: ".*Security\\$ProjectSecurity\\.yaml"
}
};

// Collect every module role defined across all modules by reading each
// module's Security$ModuleSecurity.yaml. Returns a set of "Module.Role".
function definedModuleRoles() {
const defined = new Set();
let entries;
try {
entries = mxlint.io.listdir(".");
} catch (e) {
return defined;
}
for (const entry of entries) {
try {
if (!mxlint.io.isdir(entry)) {
continue;
}
const moduleSecurity = mxlint.io.readYaml(entry + "/Security$ModuleSecurity.yaml");
if (!moduleSecurity || !moduleSecurity.ModuleRoles) {
continue;
}
for (const role of moduleSecurity.ModuleRoles) {
defined.add(entry + "." + role.Name);
}
} catch (e) {
// Not a module directory (no module security) - skip.
}
}
return defined;
}

function rule(input = {}) {
const errors = [];

// Module roles that are assigned to at least one user role.
const assigned = new Set();
const userRoles = input.UserRoles || [];
for (const userRole of userRoles) {
for (const moduleRole of (userRole.ModuleRoles || [])) {
assigned.add(moduleRole);
}
}

const defined = definedModuleRoles();
for (const moduleRole of defined) {
if (!assigned.has(moduleRole)) {
errors.push(`[${metadata.custom.severity}, ${metadata.custom.category}, ${metadata.custom.rulenumber}] Module role ${moduleRole} is not assigned to any user role.`);
}
}

const allow = errors.length === 0;
return { allow, errors };
}
Loading
Loading