zexus 1.6.2
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/LICENSE +0 -0
- package/README.md +2513 -0
- package/bin/zexus +2 -0
- package/bin/zpics +2 -0
- package/bin/zpm +2 -0
- package/bin/zx +2 -0
- package/bin/zx-deploy +2 -0
- package/bin/zx-dev +2 -0
- package/bin/zx-run +2 -0
- package/package.json +66 -0
- package/scripts/README.md +24 -0
- package/scripts/postinstall.js +44 -0
- package/shared_config.json +24 -0
- package/src/README.md +1525 -0
- package/src/tests/run_zexus_tests.py +117 -0
- package/src/tests/test_all_phases.zx +346 -0
- package/src/tests/test_blockchain_features.zx +306 -0
- package/src/tests/test_complexity_features.zx +321 -0
- package/src/tests/test_core_integration.py +185 -0
- package/src/tests/test_phase10_ecosystem.zx +177 -0
- package/src/tests/test_phase1_modifiers.zx +87 -0
- package/src/tests/test_phase2_plugins.zx +80 -0
- package/src/tests/test_phase3_security.zx +97 -0
- package/src/tests/test_phase4_vfs.zx +116 -0
- package/src/tests/test_phase5_types.zx +117 -0
- package/src/tests/test_phase6_metaprogramming.zx +125 -0
- package/src/tests/test_phase7_optimization.zx +132 -0
- package/src/tests/test_phase9_advanced_types.zx +157 -0
- package/src/tests/test_security_features.py +419 -0
- package/src/tests/test_security_features.zx +276 -0
- package/src/tests/test_simple_zx.zx +1 -0
- package/src/tests/test_verification_simple.zx +69 -0
- package/src/zexus/__init__.py +28 -0
- package/src/zexus/__main__.py +5 -0
- package/src/zexus/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/advanced_types.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/builtin_modules.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/capability_system.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/complexity_system.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/concurrency_system.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/config.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/dependency_injection.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/ecosystem.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/environment.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/error_reporter.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/hybrid_orchestrator.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/lexer.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/metaprogramming.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/module_cache.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/object.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/optimization.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/plugin_system.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/policy_engine.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/security.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/stdlib_integration.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/strategy_recovery.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/syntax_validator.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/type_system.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/virtual_filesystem.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/zexus_ast.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/zexus_token.cpython-312.pyc +0 -0
- package/src/zexus/advanced_types.py +401 -0
- package/src/zexus/blockchain/__init__.py +40 -0
- package/src/zexus/blockchain/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/blockchain/__pycache__/crypto.cpython-312.pyc +0 -0
- package/src/zexus/blockchain/__pycache__/ledger.cpython-312.pyc +0 -0
- package/src/zexus/blockchain/__pycache__/transaction.cpython-312.pyc +0 -0
- package/src/zexus/blockchain/crypto.py +463 -0
- package/src/zexus/blockchain/ledger.py +255 -0
- package/src/zexus/blockchain/transaction.py +267 -0
- package/src/zexus/builtin_modules.py +284 -0
- package/src/zexus/builtin_plugins.py +317 -0
- package/src/zexus/capability_system.py +372 -0
- package/src/zexus/cli/__init__.py +2 -0
- package/src/zexus/cli/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/cli/__pycache__/main.cpython-312.pyc +0 -0
- package/src/zexus/cli/main.py +707 -0
- package/src/zexus/cli/zpm.py +203 -0
- package/src/zexus/compare_interpreter_compiler.py +146 -0
- package/src/zexus/compiler/__init__.py +169 -0
- package/src/zexus/compiler/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/compiler/__pycache__/lexer.cpython-312.pyc +0 -0
- package/src/zexus/compiler/__pycache__/parser.cpython-312.pyc +0 -0
- package/src/zexus/compiler/__pycache__/zexus_ast.cpython-312.pyc +0 -0
- package/src/zexus/compiler/bytecode.py +266 -0
- package/src/zexus/compiler/compat_runtime.py +277 -0
- package/src/zexus/compiler/lexer.py +257 -0
- package/src/zexus/compiler/parser.py +779 -0
- package/src/zexus/compiler/semantic.py +118 -0
- package/src/zexus/compiler/zexus_ast.py +454 -0
- package/src/zexus/complexity_system.py +575 -0
- package/src/zexus/concurrency_system.py +493 -0
- package/src/zexus/config.py +201 -0
- package/src/zexus/crypto_bridge.py +19 -0
- package/src/zexus/dependency_injection.py +423 -0
- package/src/zexus/ecosystem.py +434 -0
- package/src/zexus/environment.py +101 -0
- package/src/zexus/environment_manager.py +119 -0
- package/src/zexus/error_reporter.py +314 -0
- package/src/zexus/evaluator/__init__.py +12 -0
- package/src/zexus/evaluator/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/bytecode_compiler.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/core.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/expressions.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/functions.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/integration.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/statements.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/utils.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/bytecode_compiler.py +700 -0
- package/src/zexus/evaluator/core.py +891 -0
- package/src/zexus/evaluator/expressions.py +827 -0
- package/src/zexus/evaluator/functions.py +3989 -0
- package/src/zexus/evaluator/integration.py +396 -0
- package/src/zexus/evaluator/statements.py +4303 -0
- package/src/zexus/evaluator/utils.py +126 -0
- package/src/zexus/evaluator_original.py +2041 -0
- package/src/zexus/external_bridge.py +16 -0
- package/src/zexus/find_affected_imports.sh +155 -0
- package/src/zexus/hybrid_orchestrator.py +152 -0
- package/src/zexus/input_validation.py +259 -0
- package/src/zexus/lexer.py +571 -0
- package/src/zexus/logging.py +89 -0
- package/src/zexus/lsp/__init__.py +9 -0
- package/src/zexus/lsp/completion_provider.py +207 -0
- package/src/zexus/lsp/definition_provider.py +22 -0
- package/src/zexus/lsp/hover_provider.py +71 -0
- package/src/zexus/lsp/server.py +269 -0
- package/src/zexus/lsp/symbol_provider.py +31 -0
- package/src/zexus/metaprogramming.py +321 -0
- package/src/zexus/module_cache.py +89 -0
- package/src/zexus/module_manager.py +107 -0
- package/src/zexus/object.py +973 -0
- package/src/zexus/optimization.py +424 -0
- package/src/zexus/parser/__init__.py +31 -0
- package/src/zexus/parser/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/parser/__pycache__/parser.cpython-312.pyc +0 -0
- package/src/zexus/parser/__pycache__/strategy_context.cpython-312.pyc +0 -0
- package/src/zexus/parser/__pycache__/strategy_structural.cpython-312.pyc +0 -0
- package/src/zexus/parser/integration.py +86 -0
- package/src/zexus/parser/parser.py +3977 -0
- package/src/zexus/parser/strategy_context.py +7254 -0
- package/src/zexus/parser/strategy_structural.py +1033 -0
- package/src/zexus/persistence.py +391 -0
- package/src/zexus/plugin_system.py +290 -0
- package/src/zexus/policy_engine.py +365 -0
- package/src/zexus/profiler/__init__.py +5 -0
- package/src/zexus/profiler/profiler.py +233 -0
- package/src/zexus/purity_system.py +398 -0
- package/src/zexus/runtime/__init__.py +20 -0
- package/src/zexus/runtime/async_runtime.py +324 -0
- package/src/zexus/search_old_imports.sh +65 -0
- package/src/zexus/security.py +1407 -0
- package/src/zexus/stack_trace.py +233 -0
- package/src/zexus/stdlib/__init__.py +27 -0
- package/src/zexus/stdlib/blockchain.py +341 -0
- package/src/zexus/stdlib/compression.py +167 -0
- package/src/zexus/stdlib/crypto.py +124 -0
- package/src/zexus/stdlib/datetime.py +163 -0
- package/src/zexus/stdlib/db_mongo.py +199 -0
- package/src/zexus/stdlib/db_mysql.py +162 -0
- package/src/zexus/stdlib/db_postgres.py +163 -0
- package/src/zexus/stdlib/db_sqlite.py +133 -0
- package/src/zexus/stdlib/encoding.py +230 -0
- package/src/zexus/stdlib/fs.py +195 -0
- package/src/zexus/stdlib/http.py +219 -0
- package/src/zexus/stdlib/http_server.py +248 -0
- package/src/zexus/stdlib/json_module.py +61 -0
- package/src/zexus/stdlib/math.py +360 -0
- package/src/zexus/stdlib/os_module.py +265 -0
- package/src/zexus/stdlib/regex.py +148 -0
- package/src/zexus/stdlib/sockets.py +253 -0
- package/src/zexus/stdlib/test_framework.zx +208 -0
- package/src/zexus/stdlib/test_runner.zx +119 -0
- package/src/zexus/stdlib_integration.py +341 -0
- package/src/zexus/strategy_recovery.py +256 -0
- package/src/zexus/syntax_validator.py +356 -0
- package/src/zexus/testing/zpics.py +407 -0
- package/src/zexus/testing/zpics_runtime.py +369 -0
- package/src/zexus/type_system.py +374 -0
- package/src/zexus/validation_system.py +569 -0
- package/src/zexus/virtual_filesystem.py +355 -0
- package/src/zexus/vm/__init__.py +8 -0
- package/src/zexus/vm/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/async_optimizer.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/bytecode.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/cache.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/jit.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/memory_manager.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/memory_pool.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/optimizer.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/parallel_vm.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/peephole_optimizer.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/profiler.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/register_allocator.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/register_vm.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/ssa_converter.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/vm.cpython-312.pyc +0 -0
- package/src/zexus/vm/async_optimizer.py +420 -0
- package/src/zexus/vm/bytecode.py +428 -0
- package/src/zexus/vm/bytecode_converter.py +297 -0
- package/src/zexus/vm/cache.py +532 -0
- package/src/zexus/vm/jit.py +720 -0
- package/src/zexus/vm/memory_manager.py +520 -0
- package/src/zexus/vm/memory_pool.py +511 -0
- package/src/zexus/vm/optimizer.py +478 -0
- package/src/zexus/vm/parallel_vm.py +899 -0
- package/src/zexus/vm/peephole_optimizer.py +452 -0
- package/src/zexus/vm/profiler.py +527 -0
- package/src/zexus/vm/register_allocator.py +462 -0
- package/src/zexus/vm/register_vm.py +520 -0
- package/src/zexus/vm/ssa_converter.py +757 -0
- package/src/zexus/vm/vm.py +1392 -0
- package/src/zexus/zexus_ast.py +1782 -0
- package/src/zexus/zexus_token.py +253 -0
- package/src/zexus/zpm/__init__.py +15 -0
- package/src/zexus/zpm/installer.py +116 -0
- package/src/zexus/zpm/package_manager.py +208 -0
- package/src/zexus/zpm/publisher.py +98 -0
- package/src/zexus/zpm/registry.py +110 -0
- package/src/zexus.egg-info/PKG-INFO +2235 -0
- package/src/zexus.egg-info/SOURCES.txt +876 -0
- package/src/zexus.egg-info/dependency_links.txt +1 -0
- package/src/zexus.egg-info/entry_points.txt +3 -0
- package/src/zexus.egg-info/not-zip-safe +1 -0
- package/src/zexus.egg-info/requires.txt +14 -0
- package/src/zexus.egg-info/top_level.txt +2 -0
- package/zexus.json +14 -0
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Comprehensive tests for new security features in Zexus.
|
|
3
|
+
|
|
4
|
+
Tests cover:
|
|
5
|
+
1. Capability-based access control (CAPABILITY, GRANT, REVOKE)
|
|
6
|
+
2. Pure function enforcement (PURE, IMMUTABLE)
|
|
7
|
+
3. Data validation and sanitization (VALIDATE, SANITIZE)
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import pytest
|
|
11
|
+
from src.zexus.capability_system import (
|
|
12
|
+
CapabilityManager, CapabilityLevel, SelectivePolicy, DenyAllPolicy
|
|
13
|
+
)
|
|
14
|
+
from src.zexus.purity_system import (
|
|
15
|
+
PurityAnalyzer, PurityEnforcer, PurityViolationError, Immutability
|
|
16
|
+
)
|
|
17
|
+
from src.zexus.validation_system import (
|
|
18
|
+
ValidationSchema, StandardValidators, Sanitizer, Encoding,
|
|
19
|
+
ValidationError, ValidationManager, RegexValidator, RangeValidator
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
# ============================================================================
|
|
24
|
+
# CAPABILITY SYSTEM TESTS
|
|
25
|
+
# ============================================================================
|
|
26
|
+
|
|
27
|
+
class TestCapabilitySystem:
|
|
28
|
+
"""Test capability-based security system."""
|
|
29
|
+
|
|
30
|
+
def test_capability_grant_and_check(self):
|
|
31
|
+
"""Test granting and checking capabilities."""
|
|
32
|
+
manager = CapabilityManager()
|
|
33
|
+
|
|
34
|
+
# Grant capabilities
|
|
35
|
+
manager.grant_capability("user1", "io.read")
|
|
36
|
+
manager.grant_capability("user1", "io.write")
|
|
37
|
+
|
|
38
|
+
# Check capabilities
|
|
39
|
+
assert manager.has_capability("user1", "io.read")
|
|
40
|
+
assert manager.has_capability("user1", "io.write")
|
|
41
|
+
assert not manager.has_capability("user1", "io.delete")
|
|
42
|
+
|
|
43
|
+
def test_capability_policy_selective(self):
|
|
44
|
+
"""Test selective capability policy."""
|
|
45
|
+
policy = SelectivePolicy(["io.read", "io.write"])
|
|
46
|
+
manager = CapabilityManager(policy)
|
|
47
|
+
|
|
48
|
+
assert manager.has_capability("any_user", "io.read")
|
|
49
|
+
assert manager.has_capability("any_user", "io.write")
|
|
50
|
+
assert not manager.has_capability("any_user", "io.delete")
|
|
51
|
+
|
|
52
|
+
def test_capability_policy_deny_all(self):
|
|
53
|
+
"""Test deny-all policy."""
|
|
54
|
+
policy = DenyAllPolicy()
|
|
55
|
+
manager = CapabilityManager(policy)
|
|
56
|
+
|
|
57
|
+
assert not manager.has_capability("any_user", "io.read")
|
|
58
|
+
assert not manager.has_capability("any_user", "network.tcp")
|
|
59
|
+
|
|
60
|
+
def test_capability_audit_log(self):
|
|
61
|
+
"""Test capability audit logging."""
|
|
62
|
+
manager = CapabilityManager()
|
|
63
|
+
manager.grant_capability("user1", "io.read")
|
|
64
|
+
|
|
65
|
+
# Check capability (this logs)
|
|
66
|
+
manager.check_capability("user1", "io.read")
|
|
67
|
+
manager.check_capability("user1", "io.delete") # Denied
|
|
68
|
+
|
|
69
|
+
# Get audit log
|
|
70
|
+
log = manager.get_audit_log()
|
|
71
|
+
assert len(log) == 2
|
|
72
|
+
assert log[0]["granted"] == True
|
|
73
|
+
assert log[1]["granted"] == False
|
|
74
|
+
|
|
75
|
+
def test_base_capabilities_always_available(self):
|
|
76
|
+
"""Test that base capabilities are always available."""
|
|
77
|
+
manager = CapabilityManager(DenyAllPolicy())
|
|
78
|
+
|
|
79
|
+
# Even with deny-all policy, base capabilities should be available
|
|
80
|
+
assert manager.has_capability("user", "core.language")
|
|
81
|
+
assert manager.has_capability("user", "core.math")
|
|
82
|
+
assert manager.has_capability("user", "core.strings")
|
|
83
|
+
|
|
84
|
+
def test_required_capabilities_validation(self):
|
|
85
|
+
"""Test validation of required capabilities."""
|
|
86
|
+
manager = CapabilityManager()
|
|
87
|
+
|
|
88
|
+
# Declare required capabilities
|
|
89
|
+
manager.declare_required_capabilities("module1", ["io.read", "network.http"])
|
|
90
|
+
|
|
91
|
+
# Check if all requirements are met
|
|
92
|
+
valid, missing = manager.validate_requirements("module1")
|
|
93
|
+
assert not valid # Missing capabilities
|
|
94
|
+
assert "io.read" in missing
|
|
95
|
+
assert "network.http" in missing
|
|
96
|
+
|
|
97
|
+
# Grant the capabilities
|
|
98
|
+
manager.grant_capabilities("module1", ["io.read", "network.http"])
|
|
99
|
+
|
|
100
|
+
# Now validation should pass
|
|
101
|
+
valid, missing = manager.validate_requirements("module1")
|
|
102
|
+
assert valid
|
|
103
|
+
assert len(missing) == 0
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
# ============================================================================
|
|
107
|
+
# PURITY SYSTEM TESTS
|
|
108
|
+
# ============================================================================
|
|
109
|
+
|
|
110
|
+
class TestPuritySystem:
|
|
111
|
+
"""Test pure function enforcement."""
|
|
112
|
+
|
|
113
|
+
def test_pure_function_detection(self):
|
|
114
|
+
"""Test detection of pure functions."""
|
|
115
|
+
analyzer = PurityAnalyzer()
|
|
116
|
+
|
|
117
|
+
# Pure function
|
|
118
|
+
pure_code = """
|
|
119
|
+
function add(a, b) {
|
|
120
|
+
return a + b;
|
|
121
|
+
}
|
|
122
|
+
"""
|
|
123
|
+
sig = analyzer.analyze("add", pure_code, ["a", "b"])
|
|
124
|
+
assert sig.actual_purity.name == "PURE"
|
|
125
|
+
assert len(sig.side_effects) == 0
|
|
126
|
+
|
|
127
|
+
def test_impure_function_detection_io(self):
|
|
128
|
+
"""Test detection of I/O operations (impure)."""
|
|
129
|
+
analyzer = PurityAnalyzer()
|
|
130
|
+
|
|
131
|
+
# Impure: performs I/O
|
|
132
|
+
impure_code = """
|
|
133
|
+
function read_file(path) {
|
|
134
|
+
return open(path).read();
|
|
135
|
+
}
|
|
136
|
+
"""
|
|
137
|
+
sig = analyzer.analyze("read_file", impure_code, ["path"])
|
|
138
|
+
assert sig.actual_purity.name in ["IMPURE", "RESTRICTED"]
|
|
139
|
+
assert len(sig.side_effects) > 0
|
|
140
|
+
|
|
141
|
+
def test_impure_function_detection_global_state(self):
|
|
142
|
+
"""Test detection of global state access (impure)."""
|
|
143
|
+
analyzer = PurityAnalyzer()
|
|
144
|
+
|
|
145
|
+
# Impure: accesses global state
|
|
146
|
+
impure_code = """
|
|
147
|
+
function update_global() {
|
|
148
|
+
globals()['counter'] += 1;
|
|
149
|
+
return globals()['counter'];
|
|
150
|
+
}
|
|
151
|
+
"""
|
|
152
|
+
sig = analyzer.analyze("update_global", impure_code, [])
|
|
153
|
+
assert sig.actual_purity.name in ["IMPURE", "RESTRICTED"]
|
|
154
|
+
|
|
155
|
+
def test_impure_function_detection_exception(self):
|
|
156
|
+
"""Test detection of exception throwing (side effect)."""
|
|
157
|
+
analyzer = PurityAnalyzer()
|
|
158
|
+
|
|
159
|
+
code = """
|
|
160
|
+
function divide(a, b) {
|
|
161
|
+
if b == 0:
|
|
162
|
+
raise "Division by zero";
|
|
163
|
+
return a / b;
|
|
164
|
+
}
|
|
165
|
+
"""
|
|
166
|
+
sig = analyzer.analyze("divide", code, ["a", "b"])
|
|
167
|
+
assert len(sig.side_effects) > 0
|
|
168
|
+
|
|
169
|
+
def test_immutability_marking(self):
|
|
170
|
+
"""Test marking objects as immutable."""
|
|
171
|
+
immutability = Immutability()
|
|
172
|
+
|
|
173
|
+
data = {"name": "Alice", "age": 30}
|
|
174
|
+
immutability.mark_immutable(data)
|
|
175
|
+
|
|
176
|
+
assert immutability.is_immutable(data)
|
|
177
|
+
|
|
178
|
+
def test_immutability_nested_structures(self):
|
|
179
|
+
"""Test immutability on nested structures."""
|
|
180
|
+
immutability = Immutability()
|
|
181
|
+
|
|
182
|
+
data = {"user": {"name": "Alice", "age": 30}}
|
|
183
|
+
immutability.mark_immutable(data)
|
|
184
|
+
|
|
185
|
+
# Both outer and inner should be marked
|
|
186
|
+
assert immutability.is_immutable(data)
|
|
187
|
+
# Note: nested dict is also marked
|
|
188
|
+
assert immutability.is_immutable(data["user"])
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
# ============================================================================
|
|
192
|
+
# VALIDATION SYSTEM TESTS
|
|
193
|
+
# ============================================================================
|
|
194
|
+
|
|
195
|
+
class TestValidationSystem:
|
|
196
|
+
"""Test data validation system."""
|
|
197
|
+
|
|
198
|
+
def test_standard_email_validator(self):
|
|
199
|
+
"""Test email validation."""
|
|
200
|
+
validator = StandardValidators.EMAIL
|
|
201
|
+
|
|
202
|
+
assert validator.validate("user@example.com")
|
|
203
|
+
assert not validator.validate("invalid-email")
|
|
204
|
+
assert not validator.validate("@example.com")
|
|
205
|
+
|
|
206
|
+
def test_standard_url_validator(self):
|
|
207
|
+
"""Test URL validation."""
|
|
208
|
+
validator = StandardValidators.URL
|
|
209
|
+
|
|
210
|
+
assert validator.validate("https://example.com")
|
|
211
|
+
assert validator.validate("http://example.com/path")
|
|
212
|
+
assert not validator.validate("not a url")
|
|
213
|
+
|
|
214
|
+
def test_standard_ipv4_validator(self):
|
|
215
|
+
"""Test IPv4 validation."""
|
|
216
|
+
validator = StandardValidators.IPV4
|
|
217
|
+
|
|
218
|
+
assert validator.validate("192.168.1.1")
|
|
219
|
+
assert validator.validate("10.0.0.1")
|
|
220
|
+
assert not validator.validate("256.256.256.256")
|
|
221
|
+
assert not validator.validate("invalid.ip")
|
|
222
|
+
|
|
223
|
+
def test_range_validator(self):
|
|
224
|
+
"""Test range validation."""
|
|
225
|
+
validator = RangeValidator(min_val=0, max_val=100)
|
|
226
|
+
|
|
227
|
+
assert validator.validate(50)
|
|
228
|
+
assert validator.validate(0)
|
|
229
|
+
assert validator.validate(100)
|
|
230
|
+
assert not validator.validate(-1)
|
|
231
|
+
assert not validator.validate(101)
|
|
232
|
+
|
|
233
|
+
def test_validation_schema(self):
|
|
234
|
+
"""Test validation schema."""
|
|
235
|
+
schema = ValidationSchema({
|
|
236
|
+
"name": str,
|
|
237
|
+
"age": int,
|
|
238
|
+
"email": StandardValidators.EMAIL
|
|
239
|
+
})
|
|
240
|
+
|
|
241
|
+
# Valid data
|
|
242
|
+
valid_data = {
|
|
243
|
+
"name": "Alice",
|
|
244
|
+
"age": 30,
|
|
245
|
+
"email": "alice@example.com"
|
|
246
|
+
}
|
|
247
|
+
assert schema.validate(valid_data)
|
|
248
|
+
|
|
249
|
+
# Invalid data
|
|
250
|
+
invalid_data = {
|
|
251
|
+
"name": "Alice",
|
|
252
|
+
"age": 30,
|
|
253
|
+
"email": "invalid-email"
|
|
254
|
+
}
|
|
255
|
+
with pytest.raises(ValidationError):
|
|
256
|
+
schema.validate(invalid_data)
|
|
257
|
+
|
|
258
|
+
def test_missing_required_field(self):
|
|
259
|
+
"""Test validation of missing required field."""
|
|
260
|
+
schema = ValidationSchema({
|
|
261
|
+
"name": str,
|
|
262
|
+
"age": int
|
|
263
|
+
})
|
|
264
|
+
|
|
265
|
+
incomplete_data = {"name": "Alice"}
|
|
266
|
+
|
|
267
|
+
with pytest.raises(ValidationError) as exc_info:
|
|
268
|
+
schema.validate(incomplete_data)
|
|
269
|
+
|
|
270
|
+
assert "age" in str(exc_info.value)
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
# ============================================================================
|
|
274
|
+
# SANITIZATION SYSTEM TESTS
|
|
275
|
+
# ============================================================================
|
|
276
|
+
|
|
277
|
+
class TestSanitizationSystem:
|
|
278
|
+
"""Test input sanitization system."""
|
|
279
|
+
|
|
280
|
+
def test_html_sanitization(self):
|
|
281
|
+
"""Test HTML entity sanitization."""
|
|
282
|
+
dangerous = '<script>alert("XSS")</script>'
|
|
283
|
+
sanitized = Sanitizer.sanitize_string(dangerous, Encoding.HTML)
|
|
284
|
+
|
|
285
|
+
# Script tag should be escaped
|
|
286
|
+
assert '<script>' not in sanitized
|
|
287
|
+
assert '<' in sanitized or '&#' in sanitized
|
|
288
|
+
|
|
289
|
+
def test_url_sanitization(self):
|
|
290
|
+
"""Test URL encoding."""
|
|
291
|
+
unsafe = 'hello world & special chars!'
|
|
292
|
+
sanitized = Sanitizer.sanitize_string(unsafe, Encoding.URL)
|
|
293
|
+
|
|
294
|
+
# Spaces and special chars should be encoded
|
|
295
|
+
assert '%20' in sanitized or '+' in sanitized
|
|
296
|
+
assert '%26' in sanitized # &
|
|
297
|
+
|
|
298
|
+
def test_sql_sanitization(self):
|
|
299
|
+
"""Test SQL escape."""
|
|
300
|
+
dangerous = "user'; DROP TABLE users; --"
|
|
301
|
+
sanitized = Sanitizer.sanitize_string(dangerous, Encoding.SQL)
|
|
302
|
+
|
|
303
|
+
# Single quotes should be escaped
|
|
304
|
+
assert "''" in sanitized
|
|
305
|
+
|
|
306
|
+
def test_javascript_sanitization(self):
|
|
307
|
+
"""Test JavaScript escape."""
|
|
308
|
+
dangerous = 'var x = "hello"; alert("test");'
|
|
309
|
+
sanitized = Sanitizer.sanitize_string(dangerous, Encoding.JAVASCRIPT)
|
|
310
|
+
|
|
311
|
+
# Quotes should be escaped
|
|
312
|
+
assert '\\"' in sanitized or "\\'" in sanitized
|
|
313
|
+
|
|
314
|
+
def test_csv_sanitization(self):
|
|
315
|
+
"""Test CSV field escaping."""
|
|
316
|
+
dangerous = 'value with "quotes" and, commas'
|
|
317
|
+
sanitized = Sanitizer.sanitize_string(dangerous, Encoding.CSV)
|
|
318
|
+
|
|
319
|
+
# Should wrap in quotes and escape inner quotes
|
|
320
|
+
assert sanitized.startswith('"')
|
|
321
|
+
assert sanitized.endswith('"')
|
|
322
|
+
assert '""' in sanitized
|
|
323
|
+
|
|
324
|
+
def test_sanitize_dict(self):
|
|
325
|
+
"""Test sanitizing entire dictionary."""
|
|
326
|
+
unsafe_data = {
|
|
327
|
+
"name": '<script>alert("xss")</script>',
|
|
328
|
+
"email": "user@example.com"
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
sanitized = Sanitizer.sanitize_dict(unsafe_data, Encoding.HTML)
|
|
332
|
+
|
|
333
|
+
assert '<script>' not in sanitized["name"]
|
|
334
|
+
assert sanitized["email"] == "user@example.com"
|
|
335
|
+
|
|
336
|
+
def test_sanitize_nested_structure(self):
|
|
337
|
+
"""Test sanitizing nested structures."""
|
|
338
|
+
unsafe_data = {
|
|
339
|
+
"user": {
|
|
340
|
+
"name": '<img src=x onerror="alert()">',
|
|
341
|
+
"posts": [
|
|
342
|
+
{"title": '<script>alert("xss")</script>'}
|
|
343
|
+
]
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
sanitized = Sanitizer.sanitize_dict(unsafe_data, Encoding.HTML)
|
|
348
|
+
|
|
349
|
+
# Nested dangerous content should be sanitized
|
|
350
|
+
assert '<img' not in sanitized["user"]["name"]
|
|
351
|
+
assert '<script>' not in sanitized["user"]["posts"][0]["title"]
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
# ============================================================================
|
|
355
|
+
# INTEGRATION TESTS
|
|
356
|
+
# ============================================================================
|
|
357
|
+
|
|
358
|
+
class TestSecurityIntegration:
|
|
359
|
+
"""Integration tests combining multiple security features."""
|
|
360
|
+
|
|
361
|
+
def test_capability_with_validation(self):
|
|
362
|
+
"""Test using capabilities with validation."""
|
|
363
|
+
# User with io.read capability
|
|
364
|
+
manager = CapabilityManager()
|
|
365
|
+
manager.grant_capability("user1", "io.read")
|
|
366
|
+
|
|
367
|
+
# Validate file path
|
|
368
|
+
schema = ValidationSchema({
|
|
369
|
+
"path": StandardValidators.ALPHANUMERIC
|
|
370
|
+
})
|
|
371
|
+
|
|
372
|
+
file_data = {"path": "/path/to/file"}
|
|
373
|
+
|
|
374
|
+
# Both capability check and validation should pass
|
|
375
|
+
assert manager.has_capability("user1", "io.read")
|
|
376
|
+
assert schema.validate(file_data)
|
|
377
|
+
|
|
378
|
+
def test_purity_with_immutability(self):
|
|
379
|
+
"""Test pure functions with immutable data."""
|
|
380
|
+
analyzer = PurityAnalyzer()
|
|
381
|
+
immutability = Immutability()
|
|
382
|
+
|
|
383
|
+
# Pure function with immutable inputs
|
|
384
|
+
pure_code = """
|
|
385
|
+
function sum(numbers) {
|
|
386
|
+
total = 0;
|
|
387
|
+
for num in numbers:
|
|
388
|
+
total = total + num;
|
|
389
|
+
return total;
|
|
390
|
+
}
|
|
391
|
+
"""
|
|
392
|
+
|
|
393
|
+
sig = analyzer.analyze("sum", pure_code, ["numbers"])
|
|
394
|
+
|
|
395
|
+
# Immutable input list
|
|
396
|
+
numbers = [1, 2, 3, 4, 5]
|
|
397
|
+
immutability.mark_immutable(numbers)
|
|
398
|
+
|
|
399
|
+
assert sig.actual_purity.name == "PURE"
|
|
400
|
+
assert immutability.is_immutable(numbers)
|
|
401
|
+
|
|
402
|
+
def test_sanitize_then_validate(self):
|
|
403
|
+
"""Test sanitizing input then validating it."""
|
|
404
|
+
# Untrusted input
|
|
405
|
+
user_input = '<img src=x onerror="alert()"> alice@example.com'
|
|
406
|
+
|
|
407
|
+
# Sanitize
|
|
408
|
+
sanitized = Sanitizer.sanitize_string(user_input, Encoding.HTML)
|
|
409
|
+
|
|
410
|
+
# Then extract email part and validate
|
|
411
|
+
email_part = "alice@example.com"
|
|
412
|
+
validator = StandardValidators.EMAIL
|
|
413
|
+
|
|
414
|
+
assert validator.validate(email_part)
|
|
415
|
+
assert '<img' not in sanitized
|
|
416
|
+
|
|
417
|
+
|
|
418
|
+
if __name__ == "__main__":
|
|
419
|
+
pytest.main([__file__, "-v"])
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
# Test file for Security Features
|
|
2
|
+
# Tests: Capability System, Validation, Sanitization, Immutability
|
|
3
|
+
|
|
4
|
+
# ============================================================================
|
|
5
|
+
# TEST 1: Capability Definition
|
|
6
|
+
# ============================================================================
|
|
7
|
+
print "=== Test 1: Capability Definition ===";
|
|
8
|
+
|
|
9
|
+
capability read_file;
|
|
10
|
+
capability write_file;
|
|
11
|
+
capability delete_file;
|
|
12
|
+
capability network_access;
|
|
13
|
+
|
|
14
|
+
print "✓ Capabilities defined";
|
|
15
|
+
|
|
16
|
+
# ============================================================================
|
|
17
|
+
# TEST 2: Grant Capabilities
|
|
18
|
+
# ============================================================================
|
|
19
|
+
print "=== Test 2: Grant Capabilities ===";
|
|
20
|
+
|
|
21
|
+
grant user1 read_file;
|
|
22
|
+
grant user1 write_file;
|
|
23
|
+
grant admin read_file;
|
|
24
|
+
grant admin write_file;
|
|
25
|
+
grant admin delete_file;
|
|
26
|
+
|
|
27
|
+
print "✓ Capabilities granted";
|
|
28
|
+
|
|
29
|
+
# ============================================================================
|
|
30
|
+
# TEST 3: Revoke Capabilities
|
|
31
|
+
# ============================================================================
|
|
32
|
+
print "=== Test 3: Revoke Capabilities ===";
|
|
33
|
+
|
|
34
|
+
revoke user1 write_file;
|
|
35
|
+
revoke user1 read_file;
|
|
36
|
+
|
|
37
|
+
print "✓ Capabilities revoked";
|
|
38
|
+
|
|
39
|
+
# ============================================================================
|
|
40
|
+
# TEST 4: Multiple Grants
|
|
41
|
+
# ============================================================================
|
|
42
|
+
print "=== Test 4: Multiple Entity Capabilities ===";
|
|
43
|
+
|
|
44
|
+
grant service_account read_file;
|
|
45
|
+
grant service_account write_file;
|
|
46
|
+
grant service_account network_access;
|
|
47
|
+
|
|
48
|
+
print "✓ Service account granted multiple capabilities";
|
|
49
|
+
|
|
50
|
+
# ============================================================================
|
|
51
|
+
# TEST 5: Validate Statement
|
|
52
|
+
# ============================================================================
|
|
53
|
+
print "=== Test 5: Data Validation ===";
|
|
54
|
+
|
|
55
|
+
let email_data = "user@example.com";
|
|
56
|
+
validate email_data using "email";
|
|
57
|
+
|
|
58
|
+
print "✓ Email validation passed";
|
|
59
|
+
|
|
60
|
+
let number_data = 42;
|
|
61
|
+
validate number_data using "integer";
|
|
62
|
+
|
|
63
|
+
print "✓ Integer validation passed";
|
|
64
|
+
|
|
65
|
+
# ============================================================================
|
|
66
|
+
# TEST 6: Sanitize HTML
|
|
67
|
+
# ============================================================================
|
|
68
|
+
print "=== Test 6: HTML Sanitization ===";
|
|
69
|
+
|
|
70
|
+
let html_input = "<script>alert('xss')</script>";
|
|
71
|
+
sanitize html_input as html;
|
|
72
|
+
|
|
73
|
+
print "✓ HTML input sanitized";
|
|
74
|
+
|
|
75
|
+
# ============================================================================
|
|
76
|
+
# TEST 7: Sanitize URL
|
|
77
|
+
# ============================================================================
|
|
78
|
+
print "=== Test 7: URL Sanitization ===";
|
|
79
|
+
|
|
80
|
+
let url_input = "https://example.com?param=value&other=test";
|
|
81
|
+
sanitize url_input as url;
|
|
82
|
+
|
|
83
|
+
print "✓ URL input sanitized";
|
|
84
|
+
|
|
85
|
+
# ============================================================================
|
|
86
|
+
# TEST 8: Sanitize SQL
|
|
87
|
+
# ============================================================================
|
|
88
|
+
print "=== Test 8: SQL Sanitization ===";
|
|
89
|
+
|
|
90
|
+
let sql_input = "SELECT * FROM users WHERE id='1 OR 1=1'";
|
|
91
|
+
sanitize sql_input as sql;
|
|
92
|
+
|
|
93
|
+
print "✓ SQL input sanitized";
|
|
94
|
+
|
|
95
|
+
# ============================================================================
|
|
96
|
+
# TEST 9: Immutable Variables
|
|
97
|
+
# ============================================================================
|
|
98
|
+
print "=== Test 9: Immutable Variables ===";
|
|
99
|
+
|
|
100
|
+
immutable let api_key = "secret-key-12345";
|
|
101
|
+
print "API Key (immutable): " + api_key;
|
|
102
|
+
|
|
103
|
+
immutable const version = "1.0.0";
|
|
104
|
+
print "Version (immutable const): " + version;
|
|
105
|
+
|
|
106
|
+
print "✓ Immutable variables created";
|
|
107
|
+
|
|
108
|
+
# ============================================================================
|
|
109
|
+
# TEST 10: Immutable Complex Data
|
|
110
|
+
# ============================================================================
|
|
111
|
+
print "=== Test 10: Immutable Data Structures ===";
|
|
112
|
+
|
|
113
|
+
immutable let config = {
|
|
114
|
+
"host": "localhost",
|
|
115
|
+
"port": 5432,
|
|
116
|
+
"database": "myapp"
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
print "Config (immutable): " + config;
|
|
120
|
+
|
|
121
|
+
# ============================================================================
|
|
122
|
+
# TEST 11: Validation with Complex Data
|
|
123
|
+
# ============================================================================
|
|
124
|
+
print "=== Test 11: Complex Data Validation ===";
|
|
125
|
+
|
|
126
|
+
let user_data = {
|
|
127
|
+
"email": "user@example.com",
|
|
128
|
+
"age": 25,
|
|
129
|
+
"name": "John Doe"
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
validate user_data using "user_schema";
|
|
133
|
+
|
|
134
|
+
print "✓ Complex user data validated";
|
|
135
|
+
|
|
136
|
+
# ============================================================================
|
|
137
|
+
# TEST 12: Multiple Sanitizations
|
|
138
|
+
# ============================================================================
|
|
139
|
+
print "=== Test 12: Multiple Sanitization Types ===";
|
|
140
|
+
|
|
141
|
+
let user_input = "<img src=x onerror=alert('xss')>";
|
|
142
|
+
sanitize user_input as html;
|
|
143
|
+
|
|
144
|
+
let csv_output = "Name,Email,Phone";
|
|
145
|
+
sanitize csv_output as csv;
|
|
146
|
+
|
|
147
|
+
let js_code = "var x = 'value'; alert(x);";
|
|
148
|
+
sanitize js_code as javascript;
|
|
149
|
+
|
|
150
|
+
print "✓ Multiple sanitization types applied";
|
|
151
|
+
|
|
152
|
+
# ============================================================================
|
|
153
|
+
# TEST 13: Capability Workflow
|
|
154
|
+
# ============================================================================
|
|
155
|
+
print "=== Test 13: Capability-Based Access Workflow ===";
|
|
156
|
+
|
|
157
|
+
# Define roles
|
|
158
|
+
capability admin_panel;
|
|
159
|
+
capability user_profile;
|
|
160
|
+
capability payment_processing;
|
|
161
|
+
|
|
162
|
+
# Grant to roles
|
|
163
|
+
grant admin admin_panel;
|
|
164
|
+
grant admin user_profile;
|
|
165
|
+
grant admin payment_processing;
|
|
166
|
+
|
|
167
|
+
grant regular_user user_profile;
|
|
168
|
+
|
|
169
|
+
grant payment_service payment_processing;
|
|
170
|
+
|
|
171
|
+
print "✓ Role-based capability system setup";
|
|
172
|
+
|
|
173
|
+
# ============================================================================
|
|
174
|
+
# TEST 14: Immutable with Capability
|
|
175
|
+
# ============================================================================
|
|
176
|
+
print "=== Test 14: Immutable Credentials ===";
|
|
177
|
+
|
|
178
|
+
immutable let db_password = "super-secret-123";
|
|
179
|
+
immutable let api_token = "token-abc-def-ghi";
|
|
180
|
+
|
|
181
|
+
capability database_access;
|
|
182
|
+
capability api_access;
|
|
183
|
+
|
|
184
|
+
grant database_service database_access;
|
|
185
|
+
grant api_service api_access;
|
|
186
|
+
|
|
187
|
+
print "✓ Immutable credentials protected";
|
|
188
|
+
|
|
189
|
+
# ============================================================================
|
|
190
|
+
# TEST 15: Validation Chain
|
|
191
|
+
# ============================================================================
|
|
192
|
+
print "=== Test 15: Validation Pipeline ===";
|
|
193
|
+
|
|
194
|
+
let phone = "+1-555-1234";
|
|
195
|
+
validate phone using "phone";
|
|
196
|
+
|
|
197
|
+
let uuid = "550e8400-e29b-41d4-a716-446655440000";
|
|
198
|
+
validate uuid using "uuid";
|
|
199
|
+
|
|
200
|
+
let ipv4 = "192.168.1.1";
|
|
201
|
+
validate ipv4 using "ipv4";
|
|
202
|
+
|
|
203
|
+
print "✓ Multiple validations in pipeline";
|
|
204
|
+
|
|
205
|
+
# ============================================================================
|
|
206
|
+
# TEST 16: Sanitize JavaScript
|
|
207
|
+
# ============================================================================
|
|
208
|
+
print "=== Test 16: JavaScript Sanitization ===";
|
|
209
|
+
|
|
210
|
+
let js_input = "eval(JSON.parse(userInput))";
|
|
211
|
+
sanitize js_input as javascript;
|
|
212
|
+
|
|
213
|
+
print "✓ Dangerous JavaScript code sanitized";
|
|
214
|
+
|
|
215
|
+
# ============================================================================
|
|
216
|
+
# TEST 17: Immutable Collections
|
|
217
|
+
# ============================================================================
|
|
218
|
+
print "=== Test 17: Immutable Collections ===";
|
|
219
|
+
|
|
220
|
+
immutable let allowed_origins = ["https://example.com", "https://app.example.com"];
|
|
221
|
+
immutable let admin_emails = ["admin@example.com", "root@example.com"];
|
|
222
|
+
|
|
223
|
+
print "Allowed origins (immutable list): " + allowed_origins;
|
|
224
|
+
print "Admin emails (immutable list): " + admin_emails;
|
|
225
|
+
|
|
226
|
+
# ============================================================================
|
|
227
|
+
# TEST 18: Capability Inheritance
|
|
228
|
+
# ============================================================================
|
|
229
|
+
print "=== Test 18: Capability Grant Pattern ===";
|
|
230
|
+
|
|
231
|
+
capability document_read;
|
|
232
|
+
capability document_write;
|
|
233
|
+
capability document_delete;
|
|
234
|
+
|
|
235
|
+
grant editor document_read;
|
|
236
|
+
grant editor document_write;
|
|
237
|
+
|
|
238
|
+
grant author document_read;
|
|
239
|
+
grant author document_write;
|
|
240
|
+
|
|
241
|
+
grant viewer document_read;
|
|
242
|
+
|
|
243
|
+
print "✓ Role-based capability hierarchy";
|
|
244
|
+
|
|
245
|
+
# ============================================================================
|
|
246
|
+
# TEST 19: Mixed Security Checks
|
|
247
|
+
# ============================================================================
|
|
248
|
+
print "=== Test 19: Combined Security Checks ===";
|
|
249
|
+
|
|
250
|
+
capability user_data_access;
|
|
251
|
+
grant privacy_officer user_data_access;
|
|
252
|
+
|
|
253
|
+
immutable let privacy_policy = "All data encrypted at rest and in transit";
|
|
254
|
+
print "Privacy policy: " + privacy_policy;
|
|
255
|
+
|
|
256
|
+
let pii = "john.doe@example.com";
|
|
257
|
+
validate pii using "email";
|
|
258
|
+
sanitize pii as html;
|
|
259
|
+
|
|
260
|
+
print "✓ PII data validated and sanitized";
|
|
261
|
+
|
|
262
|
+
# ============================================================================
|
|
263
|
+
# TEST 20: Security Audit Trail
|
|
264
|
+
# ============================================================================
|
|
265
|
+
print "=== Test 20: Security Patterns ===";
|
|
266
|
+
|
|
267
|
+
print "";
|
|
268
|
+
print "Security Features Summary:";
|
|
269
|
+
print " ✓ Capabilities: Defined and granted";
|
|
270
|
+
print " ✓ Validation: Email, phone, UUID, IPv4";
|
|
271
|
+
print " ✓ Sanitization: HTML, URL, SQL, JavaScript, CSV";
|
|
272
|
+
print " ✓ Immutability: Variables and data protected";
|
|
273
|
+
print " ✓ RBAC: Role-based access control";
|
|
274
|
+
print " ✓ Credentials: Immutable secrets";
|
|
275
|
+
print "";
|
|
276
|
+
print "All Security Tests Completed!";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function greet(name) { print("Hello, " + name); } greet("World");
|