Skip to content
Merged
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
10 changes: 6 additions & 4 deletions src/frameforge/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from pathlib import Path
from urllib.parse import urlsplit
from importlib.resources import files
from .semantic import evaluate, validate_rules
from .semantic import evaluate, mask_comments, validate_rules
from .plugin_checks import run as run_plugin_checks, validate_profile_checks
from .remediation import advise as advise_warnings
from .custom_standards import summarize as summarize_custom_standards
Expand Down Expand Up @@ -125,9 +125,11 @@ def professional_preview(root, manifest):
content = safe.read_text(encoding='utf-8')
except (OSError, UnicodeError):
continue
pattern = (r'//[^\n]*|/\*[\s\S]*?\*/' if path.suffix in ('.cs','.asmdef')
else r'--\[\[[\s\S]*?\]\]|--[^\n]*')
content = re.sub(pattern, lambda m: re.sub(r'[^\n]', ' ', m.group()), content)
if path.suffix == '.cs':
content = mask_comments(content, 'csharp')
elif path.suffix == '.lua':
content = mask_comments(content, 'lua')
# .asmdef is JSON: do not apply C# comment rules to JSON string values.
evidence.append((rel, content))
if len(evidence) >= 150:
break
Expand Down
40 changes: 23 additions & 17 deletions src/frameforge/semantic.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,28 @@
from pathlib import Path


def mask_comments(source, language):
"""Mask real C# or Lua comments while preserving quoted string contents and line numbers."""
if language == "csharp":
pattern = re.compile(
r'(?P<string>(?P<raw_delimiter>"{3,})[\s\S]*?(?P=raw_delimiter)|@"(?:""|[^"])*"|"(?:\\.|[^"\\])*"|\'(?:\\.|[^\'\\])*\')'
r'|(?P<comment>//[^\n]*|/\*[\s\S]*?\*/)'
)
elif language == "lua":
pattern = re.compile(
r'(?P<long_string>\[(?P<eq>=*)\[[\s\S]*?\](?P=eq)\])'
r'|(?P<string>"(?:\\.|[^"\\])*"|\'(?:\\.|[^\'\\])*\')'
r'|(?P<comment>--\[(?P<comment_eq>=*)\[[\s\S]*?\](?P=comment_eq)\]|--[^\n]*)'
)
else:
raise ValueError("unsupported comment masking language")
return pattern.sub(
lambda match: re.sub(r'[^\n]', ' ', match.group())
if match.group("comment") else match.group(),
source,
)


def evaluate(root, rule):
"""Observe declared literals across bounded source paths; never claim control-flow compliance."""
root = Path(root).resolve()
Expand All @@ -16,23 +38,7 @@ def evaluate(root, rule):
except (UnicodeError, OSError):
continue
# Comment filtering is intentionally conservative; not a language parser.
language = rule["language"]
if language == "csharp":
pattern = re.compile(
r'(?P<string>(?P<raw_delimiter>"{3,})[\s\S]*?(?P=raw_delimiter)|@"(?:""|[^"])*"|"(?:\\.|[^"\\])*"|\'(?:\\.|[^\'\\])*\')'
r'|(?P<comment>//[^\n]*|/\*[\s\S]*?\*/)'
)
else:
pattern = re.compile(
r'(?P<long_string>\[(?P<eq>=*)\[[\s\S]*?\](?P=eq)\])'
r'|(?P<string>"(?:\\.|[^"\\])*"|\'(?:\\.|[^\'\\])*\')'
r'|(?P<comment>--\[(?P<comment_eq>=*)\[[\s\S]*?\](?P=comment_eq)\]|--[^\n]*)'
)
source = pattern.sub(
lambda match: re.sub(r'[^\n]', ' ', match.group())
if match.group("comment") else match.group(),
source,
)
source = mask_comments(source, rule["language"])
sources.append((relative, source))

if not sources:
Expand Down
29 changes: 29 additions & 0 deletions tests/test_professional_guidance.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,35 @@ def test_unmatched_signal_is_not_a_gap(self):
r=inspect(root)['professional_guidance']
self.assertTrue(all(item['status']=='not_evaluated' for item in r))

def test_csharp_url_string_does_not_hide_professional_guidance_signal(self):
with tempfile.TemporaryDirectory() as d:
root=Path(d)
(root/'ProjectSettings').mkdir()
(root/'ProjectSettings/ProjectVersion.txt').write_text('Unity')
source=root/'Assets/Controller.cs'
source.parent.mkdir()
source.write_text('var url = "https://example.com"; MonoBehaviour; // MonoBehaviour\n')
(root/'.frameforge').mkdir()
(root/'.frameforge/profile.json').write_text(json.dumps(
{'schema_version':1,'selected_plugins':[{'id':'unity','version':'1.0.0'}]}))
result=inspect(root)['professional_guidance']
self.assertEqual(result[0]['status'],'review_recommended')
self.assertEqual(result[0]['evidence'][0]['path'],'Assets/Controller.cs')

def test_lua_comment_marker_in_string_does_not_hide_skynet_guidance_signal(self):
with tempfile.TemporaryDirectory() as d:
root=Path(d)
(root/'Dockerfile').write_text('FROM cloudwu/skynet')
source=root/'backend/actor.lua'
source.parent.mkdir()
source.write_text('local marker = "-- text"; skynet.start(function() end) -- skynet.start(false)\n')
(root/'.frameforge').mkdir()
(root/'.frameforge/profile.json').write_text(json.dumps(
{'schema_version':1,'selected_plugins':[{'id':'skynet','version':'1.0.0'}]}))
result=inspect(root)['professional_guidance']
self.assertEqual(result[0]['status'],'review_recommended')
self.assertEqual(result[0]['evidence'][0]['path'],'backend/actor.lua')

def test_comments_not_treated_as_signals(self):
with tempfile.TemporaryDirectory() as d:
root=Path(d)
Expand Down
Loading