├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── feature_request.md │ └── new-framework-support.md └── workflows │ ├── cd.yaml │ ├── ci.yaml │ └── linter.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── analyser_architecture ├── README.md ├── build.gradle.kts └── src │ ├── main │ ├── kotlin │ │ └── org │ │ │ └── archguard │ │ │ └── architecture │ │ │ ├── core │ │ │ ├── Component.kt │ │ │ ├── Workspace.kt │ │ │ ├── WorkspaceArchitecture.kt │ │ │ └── module │ │ │ │ ├── ArchitectureView.kt │ │ │ │ └── view │ │ │ │ ├── code │ │ │ │ ├── BuildTool.kt │ │ │ │ ├── CodeArchitecture.kt │ │ │ │ ├── CodeType.kt │ │ │ │ └── LangType.kt │ │ │ │ ├── concept │ │ │ │ ├── ConceptArchitecture.kt │ │ │ │ ├── ConceptType.kt │ │ │ │ └── DomainModel.kt │ │ │ │ ├── execution │ │ │ │ ├── Component.kt │ │ │ │ ├── ConnectionType.kt │ │ │ │ ├── ConnectorStyle.kt │ │ │ │ └── ExecutionArchitecture.kt │ │ │ │ └── module │ │ │ │ ├── ModuleArchitecture.kt │ │ │ │ ├── ddd │ │ │ │ └── DDDArchitecture.kt │ │ │ │ ├── layer │ │ │ │ ├── LayeredArchitecture.kt │ │ │ │ ├── MComponent.kt │ │ │ │ ├── MConnector.kt │ │ │ │ ├── MLayer.kt │ │ │ │ ├── MModule.kt │ │ │ │ ├── MPort.kt │ │ │ │ └── MRole.kt │ │ │ │ ├── microkernel │ │ │ │ └── MicroKernelArchitecture.kt │ │ │ │ ├── moduleddd │ │ │ │ └── ModuledDDDArchitecture.kt │ │ │ │ ├── mvc │ │ │ │ └── MVCArchitecture.kt │ │ │ │ └── pipesandfilters │ │ │ │ └── PipesAndFiltersArchitecture.kt │ │ │ └── detect │ │ │ ├── ArchitectureDetect.kt │ │ │ ├── FrameworkMarkup.kt │ │ │ └── LayeredIdentify.kt │ └── resources │ │ └── framework-maps.json │ └── test │ └── kotlin │ └── org │ └── archguard │ └── architecture │ ├── core │ └── ComponentTest.kt │ └── detect │ ├── ArchitectureDetectTest.kt │ ├── FrameworkMarkupTest.kt │ └── LayeredIdentifyTest.kt ├── analyser_diff_changes ├── .gitignore ├── README.md ├── build.gradle.kts └── src │ ├── main │ └── kotlin │ │ └── org │ │ └── archguard │ │ └── scanner │ │ └── analyser │ │ ├── DiffChangesAnalyser.kt │ │ └── diffchanges │ │ └── GitDiffer.kt │ └── test │ └── kotlin │ └── org │ └── archguard │ └── scanner │ └── analyser │ └── DiffChangesAnalyserTest.kt ├── analyser_git ├── build.gradle.kts └── src │ ├── main │ ├── kotlin │ │ └── org │ │ │ └── archguard │ │ │ └── scanner │ │ │ └── analyser │ │ │ ├── GitAnalyser.kt │ │ │ ├── JGitLogAdapter.kt │ │ │ ├── ScannerService.kt │ │ │ └── language │ │ │ ├── Language.kt │ │ │ ├── LanguageService.kt │ │ │ └── LineCounter.kt │ └── resources │ │ ├── db │ │ └── migration │ │ │ └── import_data_2_cloudDB.sh │ │ ├── languages.json │ │ └── logbak.xml │ └── test │ ├── kotlin │ └── org │ │ └── archguard │ │ └── scanner │ │ └── analyser │ │ ├── GitAnalyserTest.kt │ │ └── language │ │ ├── LanguageServiceTest.kt │ │ └── LineCounterTest.kt │ └── resources │ ├── gbkfiles │ └── hello.go │ └── lines │ └── hello.go ├── analyser_sca ├── README.md ├── build.gradle.kts └── src │ ├── main │ └── kotlin │ │ └── org │ │ └── archguard │ │ └── scanner │ │ └── analyser │ │ ├── ScaAnalyser.kt │ │ └── sca │ │ ├── base │ │ ├── Finder.kt │ │ └── Parser.kt │ │ ├── gradle │ │ ├── GradleFinder.kt │ │ └── GradleParser.kt │ │ ├── maven │ │ ├── MavenFinder.kt │ │ └── MavenParser.kt │ │ └── npm │ │ ├── NpmFinder.kt │ │ └── NpmParser.kt │ └── test │ ├── kotlin │ └── org │ │ └── archguard │ │ └── scanner │ │ └── analyser │ │ ├── ScaAnalyserTest.kt │ │ └── sca │ │ ├── base │ │ └── NpmParserTest.kt │ │ ├── gradle │ │ ├── GradleFinderTest.kt │ │ └── GradleParserTest.kt │ │ └── maven │ │ ├── MavenFinderTest.kt │ │ └── MavenParserTest.kt │ └── resources │ └── fixtures │ └── maven │ └── pom.xml ├── analyser_sourcecode ├── feat_apicalls │ ├── .gitignore │ ├── build.gradle.kts │ └── src │ │ ├── main │ │ └── kotlin │ │ │ └── org │ │ │ └── archguard │ │ │ └── scanner │ │ │ └── analyser │ │ │ ├── ApiCallAnalyser.kt │ │ │ ├── backend │ │ │ ├── CSharpApiAnalyser.kt │ │ │ └── JavaApiAnalyser.kt │ │ │ └── frontend │ │ │ ├── FrontendApiAnalyser.kt │ │ │ ├── Naming.kt │ │ │ ├── identify │ │ │ ├── AxiosHttpIdentify.kt │ │ │ ├── HttpIdentify.kt │ │ │ └── UmiHttpIdentify.kt │ │ │ └── path │ │ │ └── EcmaImportPath.kt │ │ └── test │ │ ├── kotlin │ │ └── org │ │ │ └── archguard │ │ │ └── scanner │ │ │ └── analyser │ │ │ ├── ApiCallAnalyserTest.kt │ │ │ ├── backend │ │ │ └── JavaApiAnalyserTest.kt │ │ │ └── frontend │ │ │ └── FrontendApiAnalyserTest.kt │ │ └── resources │ │ ├── 2_codes.json │ │ ├── backend │ │ ├── structs_DemoController.json │ │ ├── structs_HelloController.json │ │ ├── structs_NormalController.json │ │ ├── structs_SubController.json │ │ └── structs_kotlin.json │ │ └── frontend │ │ ├── structs_api-adapter.json │ │ ├── structs_apicall.json │ │ ├── structs_interface-error.json │ │ └── structs_js-umi-request.json ├── feat_datamap │ ├── .gitignore │ ├── build.gradle.kts │ └── src │ │ ├── main │ │ └── kotlin │ │ │ └── org │ │ │ └── archguard │ │ │ └── scanner │ │ │ └── analyser │ │ │ ├── DataMapAnalyser.kt │ │ │ ├── database │ │ │ ├── MysqlAnalyser.kt │ │ │ ├── MysqlIdentApp.kt │ │ │ └── SimpleRelation.kt │ │ │ └── xml │ │ │ ├── BasedXmlHandler.kt │ │ │ ├── HandlerDispatcher.kt │ │ │ ├── XmlParser.kt │ │ │ └── mybatis │ │ │ └── MyBatisHandler.kt │ │ └── test │ │ ├── kotlin │ │ └── org │ │ │ └── archguard │ │ │ └── scanner │ │ │ └── analyser │ │ │ ├── DataMapAnalyserTest.kt │ │ │ ├── database │ │ │ ├── MysqlAnalyserTest.kt │ │ │ └── MysqlIdentAppTest.kt │ │ │ └── xml │ │ │ ├── XmlParserTest.kt │ │ │ └── mybatis │ │ │ └── MyBatisHandlerTest.kt │ │ └── resources │ │ └── mybatis │ │ ├── AuthorMapper.xml │ │ ├── BlogMapper.xml │ │ ├── OmsOrderOperateHistoryDao.xml │ │ ├── OrderMapper.xml │ │ └── PmsBrandMapper.xml ├── lang_csharp │ ├── .gitignore │ ├── build.gradle.kts │ └── src │ │ ├── main │ │ └── kotlin │ │ │ └── org │ │ │ └── archguard │ │ │ └── scanner │ │ │ └── analyser │ │ │ └── CSharpAnalyser.kt │ │ └── test │ │ ├── kotlin │ │ └── org │ │ │ └── archguard │ │ │ └── scanner │ │ │ └── analyser │ │ │ └── CSharpAnalyserTest.kt │ │ └── resources │ │ ├── basic │ │ ├── BookController.cs │ │ ├── ChapiController.cs │ │ └── DynamicController.cs │ │ └── e2e │ │ ├── ApiControllerBase.cs │ │ ├── OidcConfigurationController.cs │ │ ├── TodoItemsController.cs │ │ ├── TodoListsController.cs │ │ └── WeatherForecastController.cs ├── lang_golang │ ├── .gitignore │ ├── build.gradle.kts │ └── src │ │ ├── main │ │ └── kotlin │ │ │ └── org │ │ │ └── archguard │ │ │ └── scanner │ │ │ └── analyser │ │ │ └── GoAnalyser.kt │ │ └── test │ │ ├── kotlin │ │ └── org │ │ │ └── archguard │ │ │ └── scanner │ │ │ └── analyser │ │ │ └── GoAnalyserTest.kt │ │ └── resources │ │ └── go │ │ └── hello.go ├── lang_java │ ├── .gitignore │ ├── build.gradle.kts │ └── src │ │ ├── main │ │ └── kotlin │ │ │ └── org │ │ │ └── archguard │ │ │ └── scanner │ │ │ └── analyser │ │ │ └── JavaAnalyser.kt │ │ └── test │ │ ├── kotlin │ │ └── org │ │ │ └── archguard │ │ │ └── scanner │ │ │ └── analyser │ │ │ └── JavaAnalyserTest.kt │ │ └── resources │ │ └── spring │ │ ├── DemoController.java │ │ ├── HelloController.java │ │ ├── NormalController.java │ │ └── SubController.java ├── lang_kotlin │ ├── .gitignore │ ├── build.gradle.kts │ └── src │ │ ├── main │ │ └── kotlin │ │ │ └── org │ │ │ └── archguard │ │ │ └── scanner │ │ │ └── analyser │ │ │ └── KotlinAnalyser.kt │ │ └── test │ │ ├── kotlin │ │ └── org │ │ │ └── archguard │ │ │ └── scanner │ │ │ └── analyser │ │ │ └── KotlinAnalyserTest.kt │ │ └── resources │ │ ├── kotlin │ │ └── Hello.kt │ │ └── spring │ │ └── QualityGateClientImpl.kt ├── lang_python │ ├── .gitignore │ ├── build.gradle.kts │ └── src │ │ ├── main │ │ └── kotlin │ │ │ └── org │ │ │ └── archguard │ │ │ └── scanner │ │ │ └── analyser │ │ │ └── PythonAnalyser.kt │ │ └── test │ │ ├── kotlin │ │ └── org │ │ │ └── archguard │ │ │ └── scanner │ │ │ └── analyser │ │ │ └── PythonAnalyserTest.kt │ │ └── resources │ │ └── py │ │ └── class.py ├── lang_scala │ ├── .gitignore │ ├── build.gradle.kts │ └── src │ │ ├── main │ │ └── kotlin │ │ │ └── org │ │ │ └── archguard │ │ │ └── scanner │ │ │ └── analyser │ │ │ └── ScalaAnalyser.kt │ │ └── test │ │ ├── kotlin │ │ └── org │ │ │ └── archguard │ │ │ └── scanner │ │ │ └── analyser │ │ │ └── ScalaAnalyserTest.kt │ │ └── resources │ │ └── scala │ │ └── class.scala └── lang_typescript │ ├── .gitignore │ ├── build.gradle.kts │ └── src │ ├── main │ └── kotlin │ │ └── org │ │ └── archguard │ │ └── scanner │ │ └── analyser │ │ └── TypeScriptAnalyser.kt │ └── test │ ├── kotlin │ └── org │ │ └── archguard │ │ └── scanner │ │ └── analyser │ │ └── TypeScriptAnalyserTest.kt │ └── resources │ └── ts │ ├── api-adapter │ └── src │ │ ├── api │ │ └── module │ │ │ └── profile.ts │ │ ├── component │ │ └── QualityGateProfile.tsx │ │ └── global-cache-state │ │ └── useQualityGate.ts │ ├── apicall │ └── src │ │ ├── BadSmellThreshold │ │ └── BadSmellThreshold.tsx │ │ └── api │ │ └── addition │ │ ├── config.ts │ │ ├── evaluations.ts │ │ └── systemInfo.ts │ ├── hello-world.ts │ ├── interface-error │ └── src │ │ ├── DependenceConfig │ │ └── index.tsx │ │ └── api │ │ └── module │ │ └── dependenceConfig.ts │ └── js-umi-request │ └── src │ ├── SystemConfig.jsx │ └── system-info.js ├── build.gradle.kts ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── legacy ├── common-code-repository │ ├── build.gradle.kts │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── thoughtworks │ │ │ │ └── archguard │ │ │ │ └── infrastructure │ │ │ │ ├── DBIStore.java │ │ │ │ ├── DefaultBatchImpl.java │ │ │ │ ├── IBatch.java │ │ │ │ ├── SourceBatch.java │ │ │ │ ├── task │ │ │ │ ├── ShutdownHook.java │ │ │ │ ├── SqlExecuteRunnable.java │ │ │ │ └── SqlExecuteThreadPool.java │ │ │ │ └── utils │ │ │ │ ├── SqlGenerator.java │ │ │ │ ├── UpdateRecord.java │ │ │ │ ├── UpdateRecordKey.java │ │ │ │ ├── UpdateRecordSet.java │ │ │ │ └── UpdateRecordValue.java │ │ └── kotlin │ │ │ └── org │ │ │ └── archguard │ │ │ └── scanner │ │ │ └── common │ │ │ ├── ClassRepository.kt │ │ │ ├── ContainerRepository.kt │ │ │ ├── DatamapRepository.kt │ │ │ ├── EcmaImportPath.kt │ │ │ └── RepositoryHelper.kt │ │ └── test │ │ ├── java │ │ └── com │ │ │ └── thoughtworks │ │ │ └── archguard │ │ │ └── infrastructure │ │ │ └── utils │ │ │ ├── SqlGeneratorTest.java │ │ │ └── UpdateRecordKeyTest.java │ │ └── kotlin │ │ └── com │ │ └── thoughtworks │ │ └── archguard │ │ └── infrastructure │ │ └── SourceBatchTest.kt ├── scan_bytecode │ ├── README.md │ ├── build.gradle.kts │ └── src │ │ ├── main │ │ └── kotlin │ │ │ └── org │ │ │ └── archguard │ │ │ └── scanner │ │ │ └── bytecode │ │ │ ├── ByteCodeParser.kt │ │ │ ├── CodeConstants.kt │ │ │ ├── ImportCollector.kt │ │ │ ├── Runner.kt │ │ │ └── module │ │ │ ├── CodeModule.kt │ │ │ ├── ModuleUtil.kt │ │ │ └── NoModuleException.kt │ │ └── test │ │ ├── kotlin │ │ └── org │ │ │ └── archguard │ │ │ └── scanner │ │ │ └── bytecode │ │ │ ├── ApiParserTest.kt │ │ │ ├── ByteCodeParserTest.kt │ │ │ ├── RunnerTest.kt │ │ │ └── module │ │ │ └── ModuleUtilTest.kt │ │ └── resources │ │ ├── annotation │ │ └── DemoApplication.class │ │ ├── classes │ │ ├── HelloWorld.class │ │ └── HelloWorld.java │ │ ├── controller │ │ └── CodeTreeController.class │ │ ├── e2e │ │ ├── build.gradle │ │ └── sample │ │ │ ├── CodeTreeController.class │ │ │ └── SizingRepositoryImpl.class │ │ ├── inheritance │ │ ├── Child.class │ │ ├── Hello.class │ │ └── Interface.class │ │ ├── kotlin │ │ └── QualityGateClientImpl.class │ │ ├── module │ │ └── gradle │ │ │ └── build.gradle │ │ └── scala │ │ ├── Hello.class │ │ └── Hello.scala ├── scan_jacoco │ ├── README.md │ ├── build.gradle.kts │ └── src │ │ ├── main │ │ ├── kotlin │ │ │ └── com │ │ │ │ └── thoughtworks │ │ │ │ └── archguard │ │ │ │ └── scanner │ │ │ │ └── jacoco │ │ │ │ ├── Bean2Sql.kt │ │ │ │ ├── JacocoService.kt │ │ │ │ ├── Model.kt │ │ │ │ └── Runner.kt │ │ └── resources │ │ │ ├── db │ │ │ └── migration │ │ │ │ ├── db_recreate_and_load.sh │ │ │ │ ├── ddl.sql │ │ │ │ └── import_data_2_cloudDB.sh │ │ │ └── logbak.xml │ │ └── test │ │ ├── kotlin │ │ └── com │ │ │ └── thoughtworks │ │ │ └── archguard │ │ │ └── scanner │ │ │ └── jacoco │ │ │ └── JacocoServiceTest.kt │ │ └── resources │ │ └── parent │ │ ├── classes │ │ └── CommitLog.class │ │ └── jacoco │ │ └── jacoco.exec └── scan_test_badsmell │ ├── build.gradle.kts │ └── src │ ├── main │ └── kotlin │ │ └── org │ │ └── archguard │ │ └── scanner │ │ └── tbs │ │ ├── Runner.kt │ │ └── TbsAnalyser.kt │ └── test │ ├── kotlin │ └── org │ │ └── archguard │ │ └── scanner │ │ └── tbs │ │ ├── RunnerKtTest.kt │ │ ├── RunnerTest.kt │ │ └── TbsAnalyserTest.kt │ └── resources │ ├── regression │ ├── CallAssertInClassTests.java │ ├── CreatorNotUnknownTest.java │ ├── EnvironmentSystemIntegrationTests.java │ └── I18NTest.java │ └── tbs │ ├── go │ └── empty_test.go │ └── usecases │ ├── AssertionRouletteTest.java │ ├── ConditionalTest.java │ ├── ConstructorInitializationTest.java │ ├── DuplicateAssertTest.java │ ├── EmptyTest.java │ ├── IgnoreTest.java │ ├── MagicNumberTest.java │ ├── MysteryGuestTest.java │ ├── RedundantAssertionTest.java │ ├── RedundantPrintTest.java │ ├── SleepyTest.java │ ├── TestersOnly.java │ └── UnknownTest.java ├── rule-core ├── build.gradle.kts └── src │ └── main │ └── kotlin │ └── org │ └── archguard │ └── rule │ ├── common │ ├── Casing.kt │ └── Language.kt │ └── core │ ├── IfttRule.kt │ ├── Issue.kt │ ├── IssuePosition.kt │ ├── Rule.kt │ ├── RuleSet.kt │ ├── RuleSetProvider.kt │ └── RuleVisitor.kt ├── rule-doc-generator ├── build.gradle.kts └── src │ ├── main │ └── kotlin │ │ └── org │ │ └── archguard │ │ └── doc │ │ └── generator │ │ ├── RuleDocGenerator.kt │ │ ├── Runner.kt │ │ ├── compiler │ │ ├── DocMessageCollector.kt │ │ └── KotlinAnalysis.kt │ │ └── render │ │ ├── MarkdownRenderImpl.kt │ │ └── Render.kt │ └── test │ └── kotlin │ └── org │ └── archguard │ └── doc │ └── generator │ ├── KotlinAnalysisTest.kt │ ├── RuleDocGeneratorTest.kt │ └── render │ └── CustomJekyllFrontMatterTest.kt ├── rule-linter ├── README.md ├── rule-code │ ├── build.gradle.kts │ └── src │ │ └── main │ │ ├── kotlin │ │ └── org │ │ │ └── archguard │ │ │ └── linter │ │ │ └── rule │ │ │ └── code │ │ │ ├── AstRule.kt │ │ │ ├── AstRuleSetProvider.kt │ │ │ ├── AstRuleVisitor.kt │ │ │ └── AstRulesetContext.kt │ │ └── resources │ │ └── META-INF │ │ └── services │ │ ├── org.archguard.rule.core.RuleSetProvider │ │ └── org.archguard.rule.core.RuleVisitor ├── rule-sql │ ├── README.md │ ├── build.gradle.kts │ └── src │ │ ├── main │ │ ├── kotlin │ │ │ └── org │ │ │ │ └── archguard │ │ │ │ └── linter │ │ │ │ └── rule │ │ │ │ └── sql │ │ │ │ ├── SqlRule.kt │ │ │ │ ├── SqlRuleSetProvider.kt │ │ │ │ ├── SqlRuleVisitor.kt │ │ │ │ └── rules │ │ │ │ ├── LikeStartWithoutPercentRule.kt │ │ │ │ ├── UnknownColumnSizeRule.kt │ │ │ │ ├── create │ │ │ │ ├── AtLeastOnePrimaryKeyRule.kt │ │ │ │ ├── LimitColumnSizeRule.kt │ │ │ │ ├── LimitTableNameLengthRule.kt │ │ │ │ └── SnakeCaseNamingRule.kt │ │ │ │ ├── expression │ │ │ │ └── LimitJoinsRule.kt │ │ │ │ └── insert │ │ │ │ └── InsertWithoutField.kt │ │ └── resources │ │ │ └── META-INF │ │ │ └── services │ │ │ ├── org.archguard.rule.core.RuleSetProvider │ │ │ └── org.archguard.rule.core.RuleVisitor │ │ └── test │ │ └── kotlin │ │ └── org │ │ └── archguard │ │ └── linter │ │ └── rule │ │ └── sql │ │ └── SqlRuleVisitorTest.kt ├── rule-test-code │ ├── build.gradle.kts │ └── src │ │ ├── main │ │ ├── kotlin │ │ │ └── org │ │ │ │ └── archguard │ │ │ │ └── linter │ │ │ │ └── rule │ │ │ │ └── testcode │ │ │ │ ├── TbsRule.kt │ │ │ │ ├── TestSmellRuleSetProvider.kt │ │ │ │ ├── TestSmellRuleVisitor.kt │ │ │ │ └── rules │ │ │ │ ├── DuplicateAssertRule.kt │ │ │ │ ├── EmptyTestRule.kt │ │ │ │ ├── NoIgnoreTestRule.kt │ │ │ │ ├── RedundantAssertionRule.kt │ │ │ │ ├── RedundantPrintRule.kt │ │ │ │ ├── SleepyTestRule.kt │ │ │ │ └── UnknownTestRule.kt │ │ └── resources │ │ │ └── META-INF │ │ │ └── services │ │ │ ├── org.archguard.rule.core.RuleSetProvider │ │ │ └── org.archguard.rule.core.RuleVisitor │ │ └── test │ │ └── kotlin │ │ └── org │ │ └── archguard │ │ └── linter │ │ └── rule │ │ └── testcode │ │ └── TestSmellVisitorProviderTestRule.kt └── rule-webapi │ ├── build.gradle.kts │ └── src │ ├── main │ ├── kotlin │ │ └── org │ │ │ └── archguard │ │ │ └── linter │ │ │ └── rule │ │ │ └── webapi │ │ │ ├── WebApiRule.kt │ │ │ ├── WebApiRuleSetProvider.kt │ │ │ ├── WebApiRuleVisitor.kt │ │ │ └── rules │ │ │ ├── Constants.kt │ │ │ ├── MinFeatureApiRule.kt │ │ │ ├── MultipleParametersRule.kt │ │ │ ├── NoCrudEnd.kt │ │ │ ├── NoHttpMethodInUrlRule.kt │ │ │ ├── NotUppercaseRule.kt │ │ │ ├── SpliceNamingRule.kt │ │ │ └── StartWithoutCrudRule.kt │ └── resources │ │ └── META-INF │ │ └── services │ │ ├── org.archguard.rule.core.RuleSetProvider │ │ └── org.archguard.rule.core.RuleVisitor │ └── test │ └── kotlin │ └── org │ └── archguard │ └── linter │ └── rule │ └── webapi │ └── WebApiRuleVisitorTest.kt ├── scanner_cli ├── .gitignore ├── README.md ├── build.gradle.kts └── src │ ├── main │ ├── kotlin │ │ └── org │ │ │ └── archguard │ │ │ └── scanner │ │ │ └── ctl │ │ │ ├── HttpController.kt │ │ │ ├── Runner.kt │ │ │ ├── client │ │ │ ├── ArchGuardConsoleClient.kt │ │ │ ├── ArchGuardCsvClient.kt │ │ │ ├── ArchGuardHttpClient.kt │ │ │ ├── ArchGuardJsonClient.kt │ │ │ └── ChainedArchGuardClient.kt │ │ │ ├── command │ │ │ └── ScannerCommand.kt │ │ │ ├── impl │ │ │ ├── CliDiffChangesContext.kt │ │ │ ├── CliGitContext.kt │ │ │ ├── CliScaContext.kt │ │ │ ├── CliSourceCodeContext.kt │ │ │ └── OfficialAnalyserSpecs.kt │ │ │ └── loader │ │ │ ├── AnalyserDispatcher.kt │ │ │ ├── AnalyserLoader.kt │ │ │ └── rule │ │ │ ├── RuleDispatcher.kt │ │ │ └── RuleLoader.kt │ └── resources │ │ └── logback.xml │ └── test │ ├── kotlin │ └── org │ │ └── archguard │ │ └── scanner │ │ └── ctl │ │ ├── ManualTest.kt │ │ ├── RunnerTest.kt │ │ ├── command │ │ └── ScannerCommandTest.kt │ │ ├── impl │ │ └── OfficialAnalyserSpecsTest.kt │ │ └── loader │ │ ├── AnalyserDispatcherTest.kt │ │ ├── AnalyserLoaderTest.kt │ │ └── rule │ │ └── RuleLoaderTest.kt │ └── resources │ ├── kotlin │ ├── Hello.kt │ ├── testonly-lang_kotlin-1.6.1-all.jar │ └── testonly-rule-webapi-2.0.0-alpha.2.jar │ └── logback.xml ├── scanner_core ├── README.md ├── build.gradle.kts └── src │ └── main │ └── kotlin │ └── org │ └── archguard │ └── scanner │ └── core │ ├── Analyser.kt │ ├── AnalyserSpec.kt │ ├── archtecture │ └── CodeLanguage.kt │ ├── client │ └── ArchGuardClient.kt │ ├── context │ └── Context.kt │ ├── diffchanges │ ├── ChangedCall.kt │ ├── DiffChangesAnalyser.kt │ └── DiffChangesContext.kt │ ├── git │ ├── GitAnalyser.kt │ ├── GitContext.kt │ └── GitLogs.kt │ ├── sca │ ├── CompositionDependency.kt │ ├── PackageDependencies.kt │ ├── ScaAnalyser.kt │ └── ScaContext.kt │ ├── sourcecode │ ├── ASTSourceCodeAnalyser.kt │ ├── CodeDatabaseRelation.kt │ ├── ContainerService.kt │ ├── LanguageSourceCodeAnalyser.kt │ ├── SourceCodeAnalyser.kt │ └── SourceCodeContext.kt │ └── utils │ └── CoroutinesExtension.kt └── settings.gradle.kts /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/new-framework-support.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: New framework support 3 | about: new framework support 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Which language would you to support** 11 | xxx 12 | 13 | **Example of this language HTTP API syntax** 14 | xxx 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | name: Java CI 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | 8 | strategy: 9 | matrix: 10 | os: [macos-latest, ubuntu-latest, windows-latest] 11 | runs-on: ${{ matrix.os }} 12 | 13 | steps: 14 | - uses: actions/checkout@v2 15 | - uses: actions/setup-java@v2 16 | with: 17 | java-version: '12' 18 | distribution: 'adopt' 19 | 20 | - name: Setup Gradle 21 | uses: gradle/gradle-build-action@v2 22 | 23 | - name: Execute Gradle Coverage 24 | run: ./gradlew check 25 | 26 | - name: Execute Gradle Coverage 27 | if: runner.os == 'macOS' 28 | run: bash <(curl -s https://codecov.io/bash) 29 | -------------------------------------------------------------------------------- /.github/workflows/linter.yml: -------------------------------------------------------------------------------- 1 | name: Linter 2 | 3 | on: 4 | push: 5 | pull_request: 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v2 12 | - uses: actions/setup-java@v2 13 | with: 14 | java-version: '12' 15 | distribution: 'adopt' 16 | 17 | - name: Setup Gradle 18 | uses: gradle/gradle-build-action@v2 19 | 20 | - name: Execute Gradle build 21 | run: ./gradlew ktlintCheck 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | logs 2 | target 3 | /.idea 4 | /.idea_modules 5 | /.classpath 6 | /.project 7 | /.settings 8 | /RUNNING_PID 9 | **/.idea 10 | **/.idea_modules 11 | **/.classpath 12 | **/.project 13 | **/.settings 14 | **/RUNNING_PID 15 | .vscode/ 16 | project/ 17 | .DS_Store 18 | **/.DS_Store 19 | *.iml 20 | output.sql 21 | **/target/ 22 | .gradle 23 | **/build/ 24 | !src/**/build/ 25 | 26 | # Ignore Gradle GUI config 27 | gradle-app.setting 28 | 29 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) 30 | !gradle-wrapper.jar 31 | 32 | # Avoid ignore Gradle wrappper properties 33 | !gradle-wrapper.properties 34 | 35 | # Cache of project 36 | .gradletasknamecache 37 | 38 | # Eclipse Gradle plugin generated files 39 | # Eclipse Core 40 | .project 41 | # JDT-specific (Eclipse Java Development Tools) 42 | .classpath 43 | *.sql 44 | **/bs.json 45 | apis.json 46 | nodes.json 47 | **/out 48 | component.inbounds.json 49 | scan_bytecode/src/main/java/org/archguard/scanner/bytecode/generics/* 50 | dependencies 51 | localtesting_*.json 52 | localtesting_*.csv 53 | !legacy/scan_jacoco/src/main/resources/db/migration/ddl.sql -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020~ Thoughtworks Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /analyser_architecture/README.md: -------------------------------------------------------------------------------- 1 | # 架构分析 2 | 3 | Refs: 4 | 5 | - [Architecture Description Language (ADL)](https://cio-wiki.org/wiki/Architecture_Description_Language_(ADL)) 6 | 7 | ## 通过领域生成架构特征 8 | 9 | 1. 如何识别领域知识? 10 | 11 | ## 多个子系统导入 12 | 13 | 基于 CSV, JSON, Markdown 14 | 15 | ## 基于依赖的框架映射,分析出架构分格 16 | 17 | 示例: 18 | 19 | 1. Spring Boot => 微服务架构 20 | 2. Equinox => OSGI 21 | 3. Flink, Kafka => Data => ServiceBased 22 | 23 | ## Arch 24 | 25 | ```yaml 26 | # 分析态输出 27 | - langauge: java 28 | conceptualArch: 29 | domains: [ "" ] 30 | styles: 31 | layeredStyle: [""] 32 | moduleArch: 33 | systems: [ "" ] 34 | subSystems: [ "" ] 35 | # from Gradle or maven 36 | modules: [ "" ] 37 | layers: [ "" ] 38 | interfaces: [ "" ] 39 | changeImpact: [ "" ] 40 | executionArch: 41 | # Interface description language 42 | interfaceDescriptionLanguage: [ "proto" ] 43 | messageQueue: [ "RabbitMQ", "Kafka" ] 44 | # hasProcesses 45 | processes: [ "ProcessBuilder" ] 46 | # thread 47 | # kotlin.concurrent.thread 48 | servers: [ "" ] 49 | codeArch: 50 | # from CLOC 51 | languages: [ "" ] 52 | # packageManager 53 | developmentTools: [ "" ] 54 | libraries: [ "" ] 55 | packages: [ "" ] 56 | directories: [ "" ] 57 | files: [ "" ] 58 | ``` 59 | 60 | ## 案例库 61 | 62 | ```yaml 63 | # Domain 64 | - domain: GUI 65 | characteristics: 66 | - WindowManager 67 | - domain: finance 68 | characteristics: 69 | - 并发 70 | ``` -------------------------------------------------------------------------------- /analyser_architecture/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | kotlin("jvm") version "1.6.10" 3 | kotlin("plugin.serialization") version "1.6.10" 4 | 5 | } 6 | 7 | dependencies { 8 | implementation(project(":scanner_core")) 9 | 10 | testImplementation("io.mockk:mockk:1.12.3") 11 | testImplementation("org.assertj:assertj-core:3.22.0") 12 | } 13 | -------------------------------------------------------------------------------- /analyser_architecture/src/main/kotlin/org/archguard/architecture/core/Workspace.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.architecture.core 2 | 3 | import chapi.domain.core.CodeDataStruct 4 | import org.archguard.scanner.core.sca.PackageDependencies 5 | import org.archguard.scanner.core.archtecture.CodeLanguage 6 | import org.archguard.scanner.core.sourcecode.ContainerService 7 | 8 | /** 9 | * **Workspace** is like IDE/Editor's workspace, same as to Git/SVN project. 10 | * 11 | * @property dataStructs the analysis result of projects. 12 | * @property projectDependencies the analysis result of package manager's config. 13 | * @property port the analysis result of container services. 14 | * @property languages the overview of project languages. 15 | * 16 | */ 17 | class Workspace( 18 | val dataStructs: List = listOf(), 19 | val projectDependencies: PackageDependencies = PackageDependencies("", "", "", listOf(), ""), 20 | val port: ContainerService = ContainerService(), 21 | val languages: List = listOf() 22 | ) 23 | -------------------------------------------------------------------------------- /analyser_architecture/src/main/kotlin/org/archguard/architecture/core/module/ArchitectureView.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.architecture.core.module 2 | 3 | import org.archguard.architecture.core.module.view.code.CodeArchitecture 4 | import org.archguard.architecture.core.module.view.concept.ConceptArchitecture 5 | import org.archguard.architecture.core.module.view.execution.ExecutionArchitecture 6 | import org.archguard.architecture.core.module.view.module.ModuleArchitecture 7 | 8 | class ArchitectureView( 9 | val conceptArchitecture: ConceptArchitecture, 10 | val moduleArchitecture: ModuleArchitecture, 11 | val executionArchitecture: ExecutionArchitecture, 12 | val codeArchitecture: CodeArchitecture 13 | ) 14 | 15 | -------------------------------------------------------------------------------- /analyser_architecture/src/main/kotlin/org/archguard/architecture/core/module/view/code/BuildTool.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.architecture.core.module.view.code 2 | 3 | enum class BuildTool { 4 | Maven, 5 | Gradle, 6 | Sbt 7 | } 8 | -------------------------------------------------------------------------------- /analyser_architecture/src/main/kotlin/org/archguard/architecture/core/module/view/code/CodeArchitecture.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.architecture.core.module.view.code 2 | 3 | import org.archguard.architecture.core.Workspace 4 | 5 | class CodeArchitecture(val language: LangType, val type: CodeType, val buildTool: BuildTool, val workspace: Workspace) -------------------------------------------------------------------------------- /analyser_architecture/src/main/kotlin/org/archguard/architecture/core/module/view/code/CodeType.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.architecture.core.module.view.code 2 | 3 | enum class CodeType { 4 | Interface, 5 | InterfaceImpl, 6 | Util, 7 | Lib 8 | } 9 | -------------------------------------------------------------------------------- /analyser_architecture/src/main/kotlin/org/archguard/architecture/core/module/view/code/LangType.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.architecture.core.module.view.code 2 | 3 | enum class LangType { 4 | Java, 5 | Kotlin, 6 | Scala, 7 | Clojure, 8 | Groovy 9 | } 10 | -------------------------------------------------------------------------------- /analyser_architecture/src/main/kotlin/org/archguard/architecture/core/module/view/concept/ConceptArchitecture.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.architecture.core.module.view.concept 2 | 3 | /** 4 | * A module in Maven or Gradle should focus on single responsibility in concept level. 5 | * So it should be a CComponent or a CConnector. 6 | * If it has more than one identity,may need be divided to more than one module. 7 | */ 8 | class ConceptArchitecture( 9 | val type: ConceptType, 10 | val domainModels: List, 11 | val reliability: Float, 12 | val desc: String, 13 | val comment: String 14 | ) 15 | 16 | -------------------------------------------------------------------------------- /analyser_architecture/src/main/kotlin/org/archguard/architecture/core/module/view/concept/ConceptType.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.architecture.core.module.view.concept 2 | 3 | enum class ConceptType { 4 | CComponent, 5 | CConnector 6 | } -------------------------------------------------------------------------------- /analyser_architecture/src/main/kotlin/org/archguard/architecture/core/module/view/concept/DomainModel.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.architecture.core.module.view.concept 2 | 3 | /** 4 | * should be tree structure 5 | */ 6 | class DomainModel 7 | -------------------------------------------------------------------------------- /analyser_architecture/src/main/kotlin/org/archguard/architecture/core/module/view/execution/Component.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.architecture.core.module.view.execution 2 | 3 | class Component 4 | -------------------------------------------------------------------------------- /analyser_architecture/src/main/kotlin/org/archguard/architecture/core/module/view/execution/ConnectionType.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.architecture.core.module.view.execution 2 | 3 | enum class ConnectionType { 4 | INBOUND, OUTBOUND 5 | } 6 | -------------------------------------------------------------------------------- /analyser_architecture/src/main/kotlin/org/archguard/architecture/core/module/view/execution/ConnectorStyle.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.architecture.core.module.view.execution 2 | 3 | enum class ConnectorStyle { 4 | HTTP, 5 | RPC, 6 | DependencyInjection, 7 | SQLLink, 8 | Protocol 9 | } 10 | -------------------------------------------------------------------------------- /analyser_architecture/src/main/kotlin/org/archguard/architecture/core/module/view/execution/ExecutionArchitecture.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.architecture.core.module.view.execution 2 | 3 | class ExecutionArchitecture( 4 | val connectionType: ConnectionType, 5 | val connectorStyle: ConnectorStyle, 6 | val components: List 7 | ) 8 | -------------------------------------------------------------------------------- /analyser_architecture/src/main/kotlin/org/archguard/architecture/core/module/view/module/ModuleArchitecture.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.architecture.core.module.view.module 2 | 3 | interface ModuleArchitecture 4 | 5 | class Dependency(val type: DependencyType, val dependent: String, val dependence: String) 6 | 7 | enum class DependencyType { 8 | Notify, 9 | Query, 10 | Call, 11 | Update 12 | } -------------------------------------------------------------------------------- /analyser_architecture/src/main/kotlin/org/archguard/architecture/core/module/view/module/ddd/DDDArchitecture.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.architecture.core.module.view.module.ddd 2 | 3 | import org.archguard.architecture.core.module.view.module.Dependency 4 | import org.archguard.architecture.core.module.view.module.ModuleArchitecture 5 | 6 | class DDDArchitecture( 7 | val infra: InfrastructureLayer, 8 | val application: ApplicationLayer, 9 | val domainLayer: DomainLayer, 10 | val interfaceLayer: InterfaceLayer, 11 | val dependencies: List 12 | ) : 13 | ModuleArchitecture 14 | 15 | class DomainLayer( 16 | val aggregates: List, 17 | val repositories: List, 18 | val domainServices: List, 19 | val factories: List 20 | ) 21 | 22 | class ApplicationLayer(val applicationServices: List) 23 | 24 | class InfrastructureLayer(val adaptors: List) 25 | 26 | class InterfaceLayer(val controllers: List) 27 | 28 | class ApplicationService 29 | 30 | class Aggregate 31 | 32 | class Repository 33 | 34 | class DomainService 35 | 36 | class Factory 37 | 38 | class Controller 39 | 40 | class Adaptor 41 | -------------------------------------------------------------------------------- /analyser_architecture/src/main/kotlin/org/archguard/architecture/core/module/view/module/layer/LayeredArchitecture.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.architecture.core.module.view.module.layer 2 | 3 | import org.archguard.architecture.core.module.view.module.ModuleArchitecture 4 | 5 | /** 6 | * we assume a module in maven or gradle should be a subsystem. 7 | * So in module architecture have one or more layers. 8 | */ 9 | class LayeredArchitecture(val layers: List) : ModuleArchitecture 10 | -------------------------------------------------------------------------------- /analyser_architecture/src/main/kotlin/org/archguard/architecture/core/module/view/module/layer/MComponent.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.architecture.core.module.view.module.layer 2 | 3 | class MComponent(name: String) : MModule(name) -------------------------------------------------------------------------------- /analyser_architecture/src/main/kotlin/org/archguard/architecture/core/module/view/module/layer/MConnector.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.architecture.core.module.view.module.layer 2 | 3 | class MConnector(name: String) : MModule(name) -------------------------------------------------------------------------------- /analyser_architecture/src/main/kotlin/org/archguard/architecture/core/module/view/module/layer/MLayer.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.architecture.core.module.view.module.layer 2 | 3 | /** 4 | * Layer in Module Level, one layer should contain one or more components 5 | */ 6 | class MLayer(val components: List, val name: String) 7 | -------------------------------------------------------------------------------- /analyser_architecture/src/main/kotlin/org/archguard/architecture/core/module/view/module/layer/MModule.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.architecture.core.module.view.module.layer 2 | 3 | abstract class MModule(val name: String) -------------------------------------------------------------------------------- /analyser_architecture/src/main/kotlin/org/archguard/architecture/core/module/view/module/layer/MPort.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.architecture.core.module.view.module.layer 2 | 3 | class MPort(name: String) : MModule(name) -------------------------------------------------------------------------------- /analyser_architecture/src/main/kotlin/org/archguard/architecture/core/module/view/module/layer/MRole.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.architecture.core.module.view.module.layer 2 | 3 | class MRole(name: String) : MModule(name) -------------------------------------------------------------------------------- /analyser_architecture/src/main/kotlin/org/archguard/architecture/core/module/view/module/microkernel/MicroKernelArchitecture.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.architecture.core.module.view.module.microkernel 2 | 3 | import org.archguard.architecture.core.module.view.module.ModuleArchitecture 4 | 5 | class MicroKernelArchitecture : ModuleArchitecture -------------------------------------------------------------------------------- /analyser_architecture/src/main/kotlin/org/archguard/architecture/core/module/view/module/moduleddd/ModuledDDDArchitecture.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.architecture.core.module.view.module.moduleddd 2 | 3 | import org.archguard.architecture.core.module.view.module.ModuleArchitecture 4 | 5 | class ModuledDDDArchitecture : ModuleArchitecture -------------------------------------------------------------------------------- /analyser_architecture/src/main/kotlin/org/archguard/architecture/core/module/view/module/mvc/MVCArchitecture.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.architecture.core.module.view.module.mvc 2 | 3 | import org.archguard.architecture.core.module.view.module.Dependency 4 | import org.archguard.architecture.core.module.view.module.ModuleArchitecture 5 | 6 | class MVCArchitecture( 7 | val models: List, 8 | val views: List, 9 | val controllers: List, 10 | val dependencies: List 11 | ) : 12 | ModuleArchitecture 13 | 14 | class Model 15 | 16 | class View 17 | 18 | class Controller 19 | -------------------------------------------------------------------------------- /analyser_architecture/src/main/kotlin/org/archguard/architecture/core/module/view/module/pipesandfilters/PipesAndFiltersArchitecture.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.architecture.core.module.view.module.pipesandfilters 2 | 3 | import org.archguard.architecture.core.module.view.module.ModuleArchitecture 4 | 5 | class PipesAndFiltersArchitecture : ModuleArchitecture -------------------------------------------------------------------------------- /analyser_architecture/src/main/resources/framework-maps.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "language": "Java", 4 | "core_stacks": [ 5 | "org.springframework.boot", 6 | "org.jdbi:jdbi3", 7 | "org.flywaydb" 8 | ], 9 | "app_type_mapping": { 10 | "web": [ 11 | "org.springframework.boot", 12 | "org.springframework:spring-webmvc" 13 | ], 14 | "compiler": [ 15 | "org.antlr:antlr4-runtime" 16 | ], 17 | "cli": [ 18 | "com.github.ajalt.clikt:clikt" 19 | ], 20 | "data": [ 21 | "org.apache.flink:flink-core" 22 | ] 23 | }, 24 | "protocol_mapping": { 25 | "http": [ 26 | "org.springframework.boot" 27 | ], 28 | "rpc": [ 29 | "org.apache.dubbo:dubbo" 30 | ], 31 | "databaselink": [ 32 | "com.zaxxer:HikariCP", 33 | "org.springframework.boot:spring-boot-starter-jdbc", 34 | "org.jdbi:jdbi3" 35 | ] 36 | } 37 | }, 38 | { 39 | "extends": "Java", 40 | "language": "Kotlin" 41 | } 42 | ] -------------------------------------------------------------------------------- /analyser_architecture/src/test/kotlin/org/archguard/architecture/core/ComponentTest.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.architecture.core 2 | 3 | import org.junit.jupiter.api.Test 4 | import kotlin.test.assertEquals 5 | 6 | internal class ComponentTest { 7 | @Test 8 | internal fun name() { 9 | val component = ExternalModuleDependencyComponent("root") 10 | 11 | val inbounds = listOf(GradleInbound( 12 | name = "root", 13 | artifact = "org.jdbi", 14 | group = "jdbi3-core", 15 | version = "3.8.2" 16 | )) 17 | 18 | component.ports += GradlePort( 19 | inbounds = inbounds 20 | ) 21 | 22 | assertEquals(ArchComponentType.MODULE, component.type) 23 | } 24 | } -------------------------------------------------------------------------------- /analyser_architecture/src/test/kotlin/org/archguard/architecture/detect/FrameworkMarkupTest.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.architecture.detect 2 | 3 | import org.junit.jupiter.api.Test 4 | import kotlin.test.assertEquals 5 | 6 | internal class FrameworkMarkupTest { 7 | @Test 8 | internal fun serial_json() { 9 | val markups = FrameworkMarkup.fromResource() 10 | assertEquals("Java", markups[0].language) 11 | } 12 | 13 | @Test 14 | internal fun extend_api_for_kotlin_extend_java() { 15 | val markups = FrameworkMarkup.fromResource() 16 | assertEquals("Kotlin", markups[1].language) 17 | assert(markups[1].appTypeMapping.isNotEmpty()) 18 | } 19 | 20 | @Test 21 | internal fun by_language() { 22 | val markup = FrameworkMarkup.byLanguage("Kotlin") 23 | assert(markup!!.appTypeMapping.isNotEmpty()) 24 | } 25 | } -------------------------------------------------------------------------------- /analyser_architecture/src/test/kotlin/org/archguard/architecture/detect/LayeredIdentifyTest.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.architecture.detect 2 | 3 | import org.archguard.architecture.core.CodeStructureStyle 4 | import org.junit.jupiter.api.Test 5 | import kotlin.test.assertEquals 6 | 7 | internal class LayeredIdentifyTest { 8 | @Test 9 | fun simple_ddd_match() { 10 | val packages: List = listOf( 11 | "com.thoughtworks.archguard.change.application", 12 | "com.thoughtworks.archguard.change.controller", 13 | "com.thoughtworks.archguard.change.domain", 14 | "com.thoughtworks.archguard.change.infrastructure" 15 | ) 16 | 17 | assertEquals(CodeStructureStyle.DDD, LayeredIdentify(packages).identify()) 18 | } 19 | 20 | @Test 21 | fun simple_mvc_match() { 22 | val packages: List = listOf( 23 | "com.thoughtworks.archguard.change.controller", 24 | "com.thoughtworks.archguard.change.service", 25 | "com.thoughtworks.archguard.change.repository" 26 | ) 27 | 28 | assertEquals(CodeStructureStyle.MVC, LayeredIdentify(packages).identify()) 29 | } 30 | } -------------------------------------------------------------------------------- /analyser_diff_changes/.gitignore: -------------------------------------------------------------------------------- 1 | diff-changes.json 2 | scm_diff_change.sql -------------------------------------------------------------------------------- /analyser_diff_changes/README.md: -------------------------------------------------------------------------------- 1 | # Diff Changes 2 | 3 | Increment AST check. 4 | 5 | Algorithm: 6 | 7 | 1. diff file size and change time ? 8 | 2. diff package ast 9 | 3. compare AST by files ? 10 | 11 | MVP: 12 | 13 | 1. diff changes between two commits 14 | 2. diff changes between multiple commits 15 | 16 | Impl: 17 | 18 | 1. create based version AST 19 | 2. collect changed files to new AST node 20 | 3. collection related classes and functions 21 | 22 | 23 | Diff Class 24 | 25 | 1. if class is same do nothing 26 | 2. compare for class body 27 | 1. if compare for functions by orders 28 | 2. compare field for changes 29 | -------------------------------------------------------------------------------- /analyser_diff_changes/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | application 3 | kotlin("jvm") version "1.6.10" 4 | kotlin("plugin.serialization") version "1.6.10" 5 | id("com.github.johnrengelman.shadow") version "7.0.0" 6 | } 7 | 8 | dependencies { 9 | api(project(":scanner_core")) 10 | 11 | // should get the code data from language analyser 12 | implementation("com.phodal.chapi:chapi-ast-kotlin:1.5.6") { 13 | exclude(group = "com.ibm.icu", module = "icu4j") 14 | } 15 | implementation("com.phodal.chapi:chapi-ast-java:1.5.6") { 16 | exclude(group = "com.ibm.icu", module = "icu4j") 17 | } 18 | 19 | implementation("org.eclipse.jgit:org.eclipse.jgit:6.0.0.202111291000-r") 20 | 21 | testImplementation("io.mockk:mockk:1.12.3") 22 | testImplementation("org.assertj:assertj-core:3.22.0") 23 | } 24 | 25 | application { 26 | mainClass.set("org.archguard.scanner.core.AnalyserKt") 27 | } 28 | 29 | tasks { 30 | shadowJar { 31 | dependencies { 32 | exclude(dependency("org.jetbrains.kotlin:.*:.*")) 33 | exclude(dependency("org.jetbrains.kotlinx:.*:.*")) 34 | } 35 | minimize() 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /analyser_diff_changes/src/main/kotlin/org/archguard/scanner/analyser/DiffChangesAnalyser.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.analyser 2 | 3 | import org.archguard.scanner.analyser.diffchanges.GitDiffer 4 | import org.archguard.scanner.core.diffchanges.ChangedCall 5 | import org.archguard.scanner.core.diffchanges.DiffChangesContext 6 | import org.slf4j.LoggerFactory 7 | 8 | class DiffChangesAnalyser( 9 | override val context: DiffChangesContext 10 | ) : org.archguard.scanner.core.diffchanges.DiffChangesAnalyser { 11 | private val logger = LoggerFactory.getLogger(this.javaClass) 12 | 13 | companion object { 14 | private const val SHORT_ID_LENGTH = 7 15 | } 16 | 17 | override fun analyse(): List = context.run { 18 | logger.info("diff from $since to $until on branch: $branch with path: $path") 19 | val differ = GitDiffer(path, branch, depth) 20 | val sinceRev = since.substring(0, minOf(SHORT_ID_LENGTH, since.length)) 21 | val untilRev = until.substring(0, minOf(SHORT_ID_LENGTH, until.length)) 22 | val changedCalls = differ.countBetween(sinceRev, untilRev) 23 | 24 | client.saveDiffs(changedCalls) 25 | 26 | changedCalls 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /analyser_git/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | application 3 | kotlin("jvm") version "1.6.10" 4 | kotlin("plugin.serialization") version "1.6.10" 5 | id("com.github.johnrengelman.shadow") version "7.0.0" 6 | } 7 | 8 | dependencies { 9 | api(project(":scanner_core")) 10 | 11 | implementation("org.eclipse.jgit:org.eclipse.jgit:6.0.0.202111291000-r") 12 | 13 | testImplementation("io.mockk:mockk:1.12.3") 14 | testImplementation("org.assertj:assertj-core:3.22.0") 15 | } 16 | 17 | application { 18 | mainClass.set("org.archguard.scanner.core.AnalyserKt") 19 | } 20 | 21 | tasks { 22 | shadowJar { 23 | dependencies { 24 | exclude(dependency("org.jetbrains.kotlin:.*:.*")) 25 | exclude(dependency("org.jetbrains.kotlinx:.*:.*")) 26 | } 27 | minimize() 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /analyser_git/src/main/kotlin/org/archguard/scanner/analyser/GitAnalyser.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.analyser 2 | 3 | import org.archguard.scanner.core.git.GitLogs 4 | import org.archguard.scanner.core.git.GitContext 5 | 6 | class GitAnalyser(override val context: GitContext) : org.archguard.scanner.core.git.GitAnalyser { 7 | private val service = ScannerService() 8 | 9 | override fun analyse(): GitLogs { 10 | val gitLogs = with(context) { service.scan(path, branch, startedAt, repoId) } 11 | context.client.saveGitLogs(gitLogs) 12 | return gitLogs 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /analyser_git/src/main/kotlin/org/archguard/scanner/analyser/language/Language.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.analyser.language 2 | 3 | import kotlinx.serialization.SerialName 4 | import kotlinx.serialization.Serializable 5 | 6 | @Serializable 7 | data class Quote( 8 | val start: String, 9 | val end: String, 10 | val ignoreEscape: Boolean?, 11 | val docString: Boolean? 12 | ) 13 | 14 | @Serializable 15 | data class Language( 16 | val name: String, 17 | @SerialName("line_comment") 18 | val lineComment: List? = listOf(), 19 | @SerialName("complexitychecks") 20 | val complexityChecks: List? = listOf(), 21 | val extensions: List = listOf(), 22 | val extensionFile: Boolean? = false, 23 | @SerialName("multi_line") 24 | val multiLine: List>? = listOf(), 25 | val quotes: List? = listOf(), 26 | @SerialName("nestedmultiline") 27 | val nestedMultiLine: Boolean? = false, 28 | val keywords: List? = listOf(), 29 | @SerialName("filenames") 30 | val fileNames: List? = listOf(), 31 | @SerialName("shebangs") 32 | val sheBangs: List? = listOf(), 33 | ) 34 | -------------------------------------------------------------------------------- /analyser_git/src/main/resources/db/migration/import_data_2_cloudDB.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | PRO_DIR=/Users/ygdong/git/code-scanners/scan_git 4 | REMOTE=jenkin@archguard-pipeline.southeastasia.cloudapp.azure.com 5 | WDR=/home/jenkin/sampleData4Git/ 6 | DDL=$WDR/ddl.sql 7 | DML=$WDR/output.sql 8 | 9 | ssh $REMOTE "mkdir $WDR" 10 | 11 | scp $PRO_DIR/src/main/resources/db/migration/ddl.sql $REMOTE:$DDL 12 | scp $PRO_DIR/output.sql $REMOTE:$DML 13 | 14 | ssh $REMOTE < 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /analyser_git/src/test/kotlin/org/archguard/scanner/analyser/language/LineCounterTest.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.analyser.language 2 | 3 | import org.junit.jupiter.api.Assertions 4 | import org.junit.jupiter.api.Test 5 | import java.nio.file.Paths 6 | 7 | internal class LineCounterTest { 8 | @Test 9 | internal fun testForGbkFile() { 10 | val resource = this.javaClass.classLoader.getResource("gbkfiles/hello.go")!! 11 | val path = Paths.get(resource.toURI()).toFile().absolutePath 12 | 13 | Assertions.assertEquals(9, LineCounter.byPath(path)) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /analyser_git/src/test/resources/gbkfiles/hello.go: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/archguard/scanner/c7723b67ef980af88c078da28c9d2927147daf7a/analyser_git/src/test/resources/gbkfiles/hello.go -------------------------------------------------------------------------------- /analyser_git/src/test/resources/lines/hello.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | fmt.Println("hello world") 7 | } 8 | -------------------------------------------------------------------------------- /analyser_sca/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | application 3 | kotlin("jvm") version "1.6.10" 4 | kotlin("plugin.serialization") version "1.6.10" 5 | id("com.github.johnrengelman.shadow") version "7.0.0" 6 | } 7 | 8 | dependencies { 9 | api(project(":scanner_core")) 10 | 11 | implementation("com.jayway.jsonpath:json-path:2.7.0") 12 | 13 | testImplementation("io.mockk:mockk:1.12.3") 14 | testImplementation("org.assertj:assertj-core:3.22.0") 15 | } 16 | 17 | application { 18 | mainClass.set("org.archguard.scanner.core.AnalyserKt") 19 | } 20 | 21 | tasks { 22 | shadowJar { 23 | dependencies { 24 | exclude(dependency("org.jetbrains.kotlin:.*:.*")) 25 | exclude(dependency("org.jetbrains.kotlinx:.*:.*")) 26 | } 27 | minimize() 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /analyser_sca/src/main/kotlin/org/archguard/scanner/analyser/sca/base/Finder.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.analyser.sca.base 2 | 3 | import org.archguard.scanner.core.sca.DeclFileTree 4 | import org.archguard.scanner.core.sca.PackageDependencies 5 | import java.io.File 6 | 7 | abstract class Finder { 8 | abstract val parser: Parser 9 | 10 | open fun isMatch(it: File): Boolean { 11 | return false 12 | } 13 | 14 | open fun process(path: String): List { 15 | return File(path).walk(FileWalkDirection.BOTTOM_UP) 16 | .filter { 17 | isMatch(it) 18 | } 19 | .flatMap { 20 | val file = DeclFileTree(filename = it.name, path = it.canonicalPath, content = it.readText()) 21 | parser.lookupSource(file) 22 | }.toList() 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /analyser_sca/src/main/kotlin/org/archguard/scanner/analyser/sca/base/Parser.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.analyser.sca.base 2 | 3 | import org.archguard.scanner.core.sca.DeclFileTree 4 | import org.archguard.scanner.core.sca.PackageDependencies 5 | 6 | abstract class Parser { 7 | open fun lookupSource(file: DeclFileTree): List { 8 | return listOf() 9 | } 10 | 11 | open fun lookupChildDep(file: DeclFileTree): List { 12 | return listOf() 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /analyser_sca/src/main/kotlin/org/archguard/scanner/analyser/sca/gradle/GradleFinder.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.analyser.sca.gradle 2 | 3 | import org.archguard.scanner.analyser.sca.base.Parser 4 | import org.archguard.scanner.analyser.sca.base.Finder 5 | import java.io.File 6 | 7 | class GradleFinder: Finder() { 8 | override val parser: Parser = GradleParser() 9 | 10 | override fun isMatch(it: File): Boolean { 11 | return it.isFile && it.name == "build.gradle" || it.name == "build.gradle.kts" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /analyser_sca/src/main/kotlin/org/archguard/scanner/analyser/sca/maven/MavenFinder.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.analyser.sca.maven 2 | 3 | import org.archguard.scanner.analyser.sca.base.Parser 4 | import org.archguard.scanner.analyser.sca.base.Finder 5 | import java.io.File 6 | 7 | class MavenFinder: Finder() { 8 | override val parser: Parser = MavenParser() 9 | 10 | override fun isMatch(it: File): Boolean { 11 | return it.isFile && it.name == "pom.xml" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /analyser_sca/src/main/kotlin/org/archguard/scanner/analyser/sca/npm/NpmFinder.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.analyser.sca.npm 2 | 3 | import org.archguard.scanner.analyser.sca.base.Parser 4 | import org.archguard.scanner.analyser.sca.base.Finder 5 | import java.io.File 6 | 7 | class NpmFinder: Finder() { 8 | override val parser: Parser = NpmParser() 9 | 10 | override fun isMatch(it: File): Boolean { 11 | return it.isFile && it.name == "package.json" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /analyser_sca/src/test/kotlin/org/archguard/scanner/analyser/ScaAnalyserTest.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.analyser 2 | 3 | import io.mockk.every 4 | import io.mockk.just 5 | import io.mockk.mockk 6 | import io.mockk.runs 7 | import io.mockk.verify 8 | import org.archguard.scanner.core.client.ArchGuardClient 9 | import org.archguard.scanner.core.sca.ScaContext 10 | import org.junit.jupiter.api.AfterEach 11 | import org.junit.jupiter.api.Test 12 | 13 | internal class ScaAnalyserTest { 14 | private val mockClient = mockk { 15 | every { saveDependencies(any()) } just runs 16 | } 17 | private val mockContext = mockk { 18 | every { client } returns mockClient 19 | } 20 | 21 | @AfterEach 22 | internal fun tearDown() { 23 | verify { mockClient.saveDependencies(any()) } 24 | } 25 | 26 | @Test 27 | internal fun gradle_with_maven() { 28 | every { mockContext.path } returns "." 29 | every { mockContext.language } returns "kotlin" 30 | val analyser = ScaAnalyser(mockContext) 31 | val deps = analyser.analyse() 32 | 33 | assert(deps.size >= 2) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /analyser_sca/src/test/kotlin/org/archguard/scanner/analyser/sca/base/NpmParserTest.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.analyser.sca.base 2 | 3 | import org.archguard.scanner.core.sca.DEP_SCOPE 4 | import org.archguard.scanner.core.sca.DeclFileTree 5 | import org.archguard.scanner.analyser.sca.npm.NpmParser 6 | import org.junit.jupiter.api.Test 7 | import kotlin.test.assertEquals 8 | 9 | internal class NpmParserTest { 10 | private val samplePackageJson = """{ 11 | "name": "my_package", 12 | "version": "1.0.0", 13 | "dependencies": { 14 | "my_dep": "^1.0.0", 15 | "another_dep": "~2.2.0" 16 | }, 17 | "devDependencies": { 18 | "another_dep": "~2.2.0" 19 | } 20 | } 21 | """.trimIndent() 22 | 23 | @Test 24 | fun normal_dep() { 25 | val declFileTree = DeclFileTree("package.json", "package.json", samplePackageJson) 26 | val declTree = NpmParser().lookupSource(declFileTree) 27 | 28 | assertEquals(1, declTree.size) 29 | assertEquals("my_package", declTree[0].name) 30 | assertEquals("1.0.0", declTree[0].version) 31 | assertEquals(3, declTree[0].dependencies.size) 32 | assertEquals(DEP_SCOPE.NORMAL, declTree[0].dependencies[0].scope) 33 | } 34 | 35 | @Test 36 | fun dev_scope() { 37 | val declFileTree = DeclFileTree("package.json", "package.json", samplePackageJson) 38 | val declTree = NpmParser().lookupSource(declFileTree) 39 | 40 | assertEquals(3, declTree[0].dependencies.size) 41 | assertEquals(DEP_SCOPE.DEV, declTree[0].dependencies[2].scope) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /analyser_sca/src/test/kotlin/org/archguard/scanner/analyser/sca/gradle/GradleFinderTest.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.analyser.sca.gradle 2 | 3 | import org.archguard.scanner.analyser.sca.maven.MavenFinder 4 | import org.junit.jupiter.api.Test 5 | import java.io.File 6 | 7 | internal class GradleFinderTest { 8 | @Test 9 | internal fun count_maven_module_deps() { 10 | val declTree = MavenFinder().process(File(".").absolutePath) 11 | val deps = declTree.flatMap { 12 | it.dependencies 13 | }.toTypedArray() 14 | 15 | assert(deps.isNotEmpty()) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /analyser_sca/src/test/kotlin/org/archguard/scanner/analyser/sca/maven/MavenFinderTest.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.analyser.sca.maven 2 | 3 | import org.archguard.scanner.analyser.sca.gradle.GradleFinder 4 | import org.junit.jupiter.api.Test 5 | import java.io.File 6 | 7 | internal class MavenFinderTest { 8 | @Test 9 | internal fun count_self_module_deps() { 10 | val declTree = GradleFinder().process(File(".").absolutePath) 11 | assert(declTree[0].dependencies.size >= 2) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /analyser_sca/src/test/resources/fixtures/maven/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.mycompany.app 6 | my-app 7 | 1.0-SNAPSHOT 8 | 9 | 10 | 1.7 11 | 1.7 12 | 13 | 14 | 15 | 16 | junit 17 | junit 18 | 4.12 19 | test 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /analyser_sourcecode/feat_apicalls/.gitignore: -------------------------------------------------------------------------------- 1 | api.json 2 | -------------------------------------------------------------------------------- /analyser_sourcecode/feat_apicalls/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | application 3 | kotlin("jvm") version "1.6.10" 4 | kotlin("plugin.serialization") version "1.6.10" 5 | id("com.github.johnrengelman.shadow") version "7.0.0" 6 | } 7 | 8 | dependencies { 9 | api(project(":scanner_core")) 10 | 11 | testImplementation("io.mockk:mockk:1.12.3") 12 | testImplementation("org.assertj:assertj-core:3.22.0") 13 | } 14 | 15 | application { 16 | mainClass.set("org.archguard.scanner.core.AnalyserKt") 17 | } 18 | 19 | tasks { 20 | shadowJar { 21 | dependencies { 22 | exclude(dependency("org.jetbrains.kotlin:.*:.*")) 23 | exclude(dependency("org.jetbrains.kotlinx:.*:.*")) 24 | } 25 | minimize() 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /analyser_sourcecode/feat_apicalls/src/main/kotlin/org/archguard/scanner/analyser/frontend/Naming.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.analyser.frontend 2 | 3 | import org.archguard.scanner.analyser.frontend.path.OS 4 | import org.archguard.scanner.analyser.frontend.path.getOS 5 | 6 | fun naming(moduleName: String, nodeName: String): String { 7 | var module = moduleName 8 | if (nodeName == "default") { 9 | return module 10 | } 11 | 12 | if (getOS() == OS.WINDOWS) module = module.replace("\\", "/") 13 | 14 | return "${module}::${nodeName}" 15 | } 16 | 17 | -------------------------------------------------------------------------------- /analyser_sourcecode/feat_apicalls/src/main/kotlin/org/archguard/scanner/analyser/frontend/identify/HttpIdentify.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.analyser.frontend.identify 2 | 3 | import chapi.domain.core.CodeCall 4 | import chapi.domain.core.CodeImport 5 | import org.archguard.scanner.core.sourcecode.ContainerDemand 6 | 7 | interface HttpIdentify { 8 | fun isMatch(call: CodeCall, imports: Array): Boolean 9 | fun convert(call: CodeCall): ContainerDemand 10 | } 11 | -------------------------------------------------------------------------------- /analyser_sourcecode/feat_apicalls/src/main/kotlin/org/archguard/scanner/analyser/frontend/identify/UmiHttpIdentify.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.analyser.frontend.identify 2 | 3 | import chapi.domain.core.CodeCall 4 | import chapi.domain.core.CodeImport 5 | import org.archguard.scanner.core.sourcecode.ContainerDemand 6 | 7 | class UmiHttpIdentify : HttpIdentify { 8 | override fun isMatch(call: CodeCall, imports: Array): Boolean { 9 | val imps = imports.filter { it.Source == "umi-request" } 10 | if (imps.isEmpty()) { 11 | return false 12 | } 13 | 14 | if (call.FunctionName == "request") { 15 | return true 16 | } 17 | 18 | return false 19 | } 20 | 21 | override fun convert(call: CodeCall): ContainerDemand { 22 | val url = call.Parameters[0].TypeValue 23 | val httpApi = ContainerDemand(target_url = url) 24 | 25 | for (codeProperty in call.Parameters[1].ObjectValue) { 26 | when (codeProperty.TypeValue) { 27 | "method" -> { 28 | httpApi.target_http_method = codeProperty.ObjectValue[0].TypeValue 29 | } 30 | "data" -> { 31 | httpApi.call_data = codeProperty.ObjectValue[0].TypeValue 32 | } 33 | } 34 | } 35 | 36 | return httpApi 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /analyser_sourcecode/feat_apicalls/src/test/resources/backend/structs_HelloController.json: -------------------------------------------------------------------------------- 1 | [{"NodeName":"HelloController","Type":"CLASS","Package":"com.example.springboot","FilePath":"HelloController.java","Fields":[],"MultipleExtend":[],"Implements":[],"Functions":[{"Name":"index","ReturnType":"String","MultipleReturns":[],"Parameters":[],"FunctionCalls":[],"Annotations":[{"Name":"GetMapping","KeyValues":[{"Key":"\"/\"","Value":"\"/\""}]}],"Modifiers":[],"InnerStructures":[],"InnerFunctions":[],"Position":{"StartLine":11,"StartLinePosition":11,"StopLine":13,"StopLinePosition":4},"LocalVariables":[]}],"InnerStructures":[],"Annotations":[{"Name":"RestController","KeyValues":[]},{"Name":"RequestMapping","KeyValues":[]}],"FunctionCalls":[],"Parameters":[],"Imports":[{"Source":"org.springframework.web.bind.annotation.GetMapping","UsageName":[]},{"Source":"org.springframework.web.bind.annotation.RestController","UsageName":[]}],"Exports":[],"Position":{"StartLine":8,"StartLinePosition":7,"StopLine":15}}] -------------------------------------------------------------------------------- /analyser_sourcecode/feat_apicalls/src/test/resources/backend/structs_NormalController.json: -------------------------------------------------------------------------------- 1 | [{"NodeName":"HelloController","Type":"CLASS","Package":"com.example.springboot","FilePath":"NormalController.java","Fields":[],"MultipleExtend":[],"Implements":[],"Functions":[{"Name":"index","ReturnType":"String","MultipleReturns":[],"Parameters":[],"FunctionCalls":[],"Annotations":[{"Name":"GetMapping","KeyValues":[{"Key":"\"/overview\"","Value":"\"/overview\""}]}],"Modifiers":[],"InnerStructures":[],"InnerFunctions":[],"Position":{"StartLine":11,"StartLinePosition":11,"StopLine":13,"StopLinePosition":4},"LocalVariables":[]}],"InnerStructures":[],"Annotations":[{"Name":"RestController","KeyValues":[]},{"Name":"RequestMapping","KeyValues":[{"Key":"\"/api/sub\"","Value":"\"/api/sub\""}]}],"FunctionCalls":[],"Parameters":[],"Imports":[{"Source":"org.springframework.web.bind.annotation.GetMapping","UsageName":[]},{"Source":"org.springframework.web.bind.annotation.RestController","UsageName":[]}],"Exports":[],"Position":{"StartLine":8,"StartLinePosition":7,"StopLine":15}}] -------------------------------------------------------------------------------- /analyser_sourcecode/feat_apicalls/src/test/resources/backend/structs_SubController.json: -------------------------------------------------------------------------------- 1 | [{"NodeName":"HelloController","Type":"CLASS","Package":"com.example.springboot","FilePath":"SubController.java","Fields":[],"MultipleExtend":[],"Implements":[],"Functions":[{"Name":"index","ReturnType":"String","MultipleReturns":[],"Parameters":[],"FunctionCalls":[],"Annotations":[{"Name":"GetMapping","KeyValues":[]}],"Modifiers":[],"InnerStructures":[],"InnerFunctions":[],"Position":{"StartLine":11,"StartLinePosition":11,"StopLine":13,"StopLinePosition":4},"LocalVariables":[]}],"InnerStructures":[],"Annotations":[{"Name":"RestController","KeyValues":[]},{"Name":"RequestMapping","KeyValues":[{"Key":"\"/api/sub\"","Value":"\"/api/sub\""}]}],"FunctionCalls":[],"Parameters":[],"Imports":[{"Source":"org.springframework.web.bind.annotation.GetMapping","UsageName":[]},{"Source":"org.springframework.web.bind.annotation.RestController","UsageName":[]}],"Exports":[],"Position":{"StartLine":8,"StartLinePosition":7,"StopLine":15}}] -------------------------------------------------------------------------------- /analyser_sourcecode/feat_datamap/.gitignore: -------------------------------------------------------------------------------- 1 | api.json 2 | -------------------------------------------------------------------------------- /analyser_sourcecode/feat_datamap/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | application 3 | kotlin("jvm") version "1.6.10" 4 | kotlin("plugin.serialization") version "1.6.10" 5 | id("com.github.johnrengelman.shadow") version "7.0.0" 6 | } 7 | 8 | dependencies { 9 | api(project(":scanner_core")) 10 | 11 | implementation("org.mybatis:mybatis:3.5.9") 12 | implementation("ognl:ognl:3.3.2") // for mybatis expression 13 | implementation("com.github.jsqlparser:jsqlparser:4.4") 14 | 15 | testImplementation("io.mockk:mockk:1.12.3") 16 | testImplementation("org.assertj:assertj-core:3.22.0") 17 | } 18 | 19 | application { 20 | mainClass.set("org.archguard.scanner.core.AnalyserKt") 21 | } 22 | 23 | tasks { 24 | shadowJar { 25 | dependencies { 26 | exclude(dependency("org.jetbrains.kotlin:.*:.*")) 27 | exclude(dependency("org.jetbrains.kotlinx:.*:.*")) 28 | } 29 | minimize() 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /analyser_sourcecode/feat_datamap/src/main/kotlin/org/archguard/scanner/analyser/database/MysqlIdentApp.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.analyser.database 2 | 3 | import mu.KotlinLogging 4 | import net.sf.jsqlparser.parser.CCJSqlParserUtil 5 | import net.sf.jsqlparser.statement.Statement 6 | import net.sf.jsqlparser.util.TablesNamesFinder 7 | 8 | object MysqlIdentApp { 9 | private val UPDATE_SQL = "update\\s+([a-zA-Z_]+)".toRegex() 10 | private val logger = KotlinLogging.logger {} 11 | 12 | fun analysis(sql: String): SimpleRelation? { 13 | val table = SimpleRelation() 14 | 15 | try { 16 | val statement: Statement = CCJSqlParserUtil.parse(sql) 17 | val tablesNamesFinder = TablesNamesFinder() 18 | 19 | table.tableNames = tablesNamesFinder.getTableList(statement).map { 20 | var tableName = it 21 | if (it.startsWith("`") && it.endsWith("`")) { 22 | tableName = tableName.removeSuffix("`").removePrefix("`") 23 | } 24 | 25 | tableName 26 | } 27 | } catch (e: Exception) { 28 | // try used regex to match for CRUD by tables 29 | if (UPDATE_SQL.find(sql) != null) { 30 | val tableName = UPDATE_SQL.find(sql)!!.groups[1]!!.value 31 | table.tableNames = arrayListOf(tableName) 32 | return table 33 | } 34 | 35 | logger.info("analysis failure for sql: $sql") 36 | return null 37 | } 38 | 39 | return table 40 | } 41 | } -------------------------------------------------------------------------------- /analyser_sourcecode/feat_datamap/src/main/kotlin/org/archguard/scanner/analyser/database/SimpleRelation.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.analyser.database 2 | 3 | class SimpleRelation( 4 | var tableNames: List = listOf(), 5 | val fields: HashMap = hashMapOf() 6 | ) -------------------------------------------------------------------------------- /analyser_sourcecode/feat_datamap/src/main/kotlin/org/archguard/scanner/analyser/xml/BasedXmlHandler.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.analyser.xml 2 | 3 | import org.xml.sax.helpers.DefaultHandler 4 | 5 | open class BasedXmlHandler: DefaultHandler() { 6 | open fun name(): String { 7 | return "" 8 | } 9 | 10 | open fun detect(name: String?, publicId: String?, systemId: String?): Boolean { 11 | return false 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /analyser_sourcecode/feat_datamap/src/main/kotlin/org/archguard/scanner/analyser/xml/HandlerDispatcher.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.analyser.xml 2 | 3 | import org.archguard.scanner.analyser.xml.mybatis.MyBatisHandler 4 | import org.xml.sax.ext.DefaultHandler2 5 | 6 | // todo: use like Koin: https://insert-koin.io/docs/quickstart/kotlin 7 | class HandlerDispatcher: DefaultHandler2() { 8 | private var handlerName: String = "" 9 | private val mybatisHandler: MyBatisHandler = MyBatisHandler() 10 | 11 | override fun startDTD(name: String?, publicId: String?, systemId: String?) { 12 | if(mybatisHandler.detect(name, publicId, systemId)) { 13 | this.handlerName = mybatisHandler.name() 14 | } 15 | } 16 | 17 | fun getContentHandler(): BasedXmlHandler? { 18 | when(this.handlerName) { 19 | "MyBatisHandler" -> { 20 | return mybatisHandler 21 | } 22 | } 23 | 24 | return null 25 | } 26 | 27 | fun handlerName(): String { 28 | return this.handlerName 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /analyser_sourcecode/feat_datamap/src/test/kotlin/org/archguard/scanner/analyser/DataMapAnalyserTest.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.analyser 2 | 3 | import io.mockk.clearAllMocks 4 | import io.mockk.every 5 | import io.mockk.just 6 | import io.mockk.mockk 7 | import io.mockk.runs 8 | import io.mockk.verify 9 | import org.archguard.scanner.core.client.ArchGuardClient 10 | import org.archguard.scanner.core.sourcecode.SourceCodeContext 11 | import org.junit.jupiter.api.AfterEach 12 | import org.junit.jupiter.api.BeforeEach 13 | 14 | internal class DataMapAnalyserTest { 15 | private val mockClient = mockk { 16 | every { saveDataStructure(any()) } just runs 17 | } 18 | private val mockContext = mockk { 19 | every { client } returns mockClient 20 | } 21 | 22 | @AfterEach 23 | internal fun tearDown() { 24 | verify { mockClient.saveRelation(any()) } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /analyser_sourcecode/feat_datamap/src/test/kotlin/org/archguard/scanner/analyser/xml/XmlParserTest.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.sourcecode.xml 2 | 3 | import org.archguard.scanner.analyser.xml.XmlParser 4 | import org.junit.jupiter.api.Test 5 | import kotlin.io.path.toPath 6 | import kotlin.test.assertEquals 7 | 8 | internal class XmlParserTest { 9 | @Test 10 | internal fun should_handle_mybatis() { 11 | val resource = this.javaClass.classLoader.getResource("mybatis/OmsOrderOperateHistoryDao.xml")!! 12 | val mybatisEntry = XmlParser.fromFile(resource.toURI().toPath().toString())?.processMyBatis()!! 13 | assertEquals("com.macro.mall.dao.OmsOrderOperateHistoryDao", mybatisEntry.namespace) 14 | } 15 | 16 | @Test 17 | internal fun parser_from_path() { 18 | val resource = this.javaClass.classLoader.getResource("mybatis")!! 19 | val entries = XmlParser.parseMybatis(resource.toURI().toPath().toString()) 20 | assert(entries.size > 3) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /analyser_sourcecode/feat_datamap/src/test/resources/mybatis/OmsOrderOperateHistoryDao.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | INSERT INTO oms_order_operate_history (order_id, operate_man, create_time, order_status, note) VALUES 6 | 7 | (#{item.orderId}, 8 | #{item.operateMan}, 9 | #{item.createTime,jdbcType=TIMESTAMP}, 10 | #{item.orderStatus}, 11 | #{item.note}) 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /analyser_sourcecode/lang_csharp/.gitignore: -------------------------------------------------------------------------------- 1 | structs_*.json 2 | -------------------------------------------------------------------------------- /analyser_sourcecode/lang_csharp/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | application 3 | kotlin("jvm") version "1.6.10" 4 | kotlin("plugin.serialization") version "1.6.10" 5 | id("com.github.johnrengelman.shadow") version "7.0.0" 6 | } 7 | 8 | dependencies { 9 | api(project(":scanner_core")) 10 | 11 | implementation("com.phodal.chapi:chapi-ast-csharp:1.5.6") { 12 | // around 10mb, only documents files, exclude (reuse in cli?) 13 | exclude(group = "com.ibm.icu", module = "icu4j") 14 | } 15 | 16 | testImplementation("io.mockk:mockk:1.12.3") 17 | testImplementation("org.assertj:assertj-core:3.22.0") 18 | } 19 | 20 | application { 21 | mainClass.set("org.archguard.scanner.core.AnalyserKt") 22 | } 23 | 24 | tasks { 25 | shadowJar { 26 | dependencies { 27 | exclude(dependency("org.jetbrains.kotlin:.*:.*")) 28 | exclude(dependency("org.jetbrains.kotlinx:.*:.*")) 29 | } 30 | minimize() 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /analyser_sourcecode/lang_csharp/src/main/kotlin/org/archguard/scanner/analyser/CSharpAnalyser.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.analyser 2 | 3 | import chapi.domain.core.CodeDataStruct 4 | import kotlinx.coroutines.async 5 | import kotlinx.coroutines.awaitAll 6 | import kotlinx.coroutines.runBlocking 7 | import org.archguard.scanner.core.sourcecode.LanguageSourceCodeAnalyser 8 | import org.archguard.scanner.core.sourcecode.SourceCodeContext 9 | import java.io.File 10 | 11 | class CSharpAnalyser(override val context: SourceCodeContext) : LanguageSourceCodeAnalyser { 12 | private val client = context.client 13 | private val impl = chapi.ast.csharpast.CSharpAnalyser() 14 | 15 | override fun analyse(): List = runBlocking { 16 | getFilesByPath(context.path) { 17 | it.absolutePath.endsWith(".cs") 18 | } 19 | .map { async { analysisByFile(it) } }.awaitAll() 20 | .flatten() 21 | .also { client.saveDataStructure(it) } 22 | } 23 | 24 | private fun analysisByFile(file: File): List { 25 | val codeContainer = impl.analysis(file.readContent(), file.name) 26 | return codeContainer.Containers.flatMap { container -> 27 | container.DataStructures.map { 28 | it.apply { 29 | it.Imports = codeContainer.Imports 30 | it.FilePath = file.absolutePath 31 | } 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /analyser_sourcecode/lang_csharp/src/test/resources/basic/BookController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Chapi.Controller { 4 | [Produces("application/json")] 5 | [Route("api/chapi")] 6 | public class BookController { 7 | [HttpPost] 8 | [Route("book")] 9 | public async Book CreateBook([FromBody]CreateBookDto dto) 10 | 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /analyser_sourcecode/lang_csharp/src/test/resources/basic/ChapiController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Chapi.Controller { 4 | [RoutePrefix("api")] 5 | public class ChapiController { 6 | [HttpGet] 7 | [Route("book/")] 8 | public Book GetBook() 9 | { 10 | return new Book(); 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /analyser_sourcecode/lang_csharp/src/test/resources/basic/DynamicController.cs: -------------------------------------------------------------------------------- 1 | namespace Chapi.Controller { 2 | [Route("api/[controller]")] 3 | class DynamicController { 4 | [HttpGet] 5 | [Route("dynamic")] 6 | public async Book GetDynamic(long? id) 7 | 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /analyser_sourcecode/lang_csharp/src/test/resources/e2e/ApiControllerBase.cs: -------------------------------------------------------------------------------- 1 | using MediatR; 2 | 3 | using Microsoft.AspNetCore.Mvc; 4 | 5 | namespace CleanArchitecture.WebUI.Controllers; 6 | 7 | [ApiController] 8 | [Route("api/[controller]")] 9 | public abstract class ApiControllerBase : ControllerBase 10 | { 11 | private ISender _mediator = null!; 12 | 13 | protected ISender Mediator => _mediator ??= HttpContext.RequestServices.GetRequiredService(); 14 | } 15 | -------------------------------------------------------------------------------- /analyser_sourcecode/lang_csharp/src/test/resources/e2e/OidcConfigurationController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.ApiAuthorization.IdentityServer; 2 | using Microsoft.AspNetCore.Mvc; 3 | 4 | namespace CleanArchitecture.WebUI.Controllers; 5 | 6 | [ApiExplorerSettings(IgnoreApi = true)] 7 | public class OidcConfigurationController : Controller 8 | { 9 | private readonly ILogger logger; 10 | 11 | public OidcConfigurationController(IClientRequestParametersProvider clientRequestParametersProvider, ILogger _logger) 12 | { 13 | ClientRequestParametersProvider = clientRequestParametersProvider; 14 | logger = _logger; 15 | } 16 | 17 | public IClientRequestParametersProvider ClientRequestParametersProvider { get; } 18 | 19 | [HttpGet("_configuration/{clientId}")] 20 | public IActionResult GetClientRequestParameters([FromRoute] string clientId) 21 | { 22 | var parameters = ClientRequestParametersProvider.GetClientParameters(HttpContext, clientId); 23 | return Ok(parameters); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /analyser_sourcecode/lang_csharp/src/test/resources/e2e/WeatherForecastController.cs: -------------------------------------------------------------------------------- 1 | using CleanArchitecture.Application.WeatherForecasts.Queries.GetWeatherForecasts; 2 | using Microsoft.AspNetCore.Mvc; 3 | 4 | namespace CleanArchitecture.WebUI.Controllers; 5 | 6 | public class WeatherForecastController : ApiControllerBase 7 | { 8 | [HttpGet] 9 | public async Task> Get() 10 | { 11 | return await Mediator.Send(new GetWeatherForecastsQuery()); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /analyser_sourcecode/lang_golang/.gitignore: -------------------------------------------------------------------------------- 1 | structs_*.json 2 | -------------------------------------------------------------------------------- /analyser_sourcecode/lang_golang/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | application 3 | kotlin("jvm") version "1.6.10" 4 | kotlin("plugin.serialization") version "1.6.10" 5 | id("com.github.johnrengelman.shadow") version "7.0.0" 6 | } 7 | 8 | dependencies { 9 | api(project(":scanner_core")) 10 | 11 | implementation("com.phodal.chapi:chapi-ast-go:1.5.6") { 12 | // around 10mb, only documents files, exclude (reuse in cli?) 13 | exclude(group = "com.ibm.icu", module = "icu4j") 14 | } 15 | 16 | testImplementation("io.mockk:mockk:1.12.3") 17 | testImplementation("org.assertj:assertj-core:3.22.0") 18 | } 19 | 20 | application { 21 | mainClass.set("org.archguard.scanner.core.AnalyserKt") 22 | } 23 | 24 | tasks { 25 | shadowJar { 26 | dependencies { 27 | exclude(dependency("org.jetbrains.kotlin:.*:.*")) 28 | exclude(dependency("org.jetbrains.kotlinx:.*:.*")) 29 | } 30 | minimize() 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /analyser_sourcecode/lang_golang/src/main/kotlin/org/archguard/scanner/analyser/GoAnalyser.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.analyser 2 | 3 | import chapi.domain.core.CodeDataStruct 4 | import kotlinx.coroutines.async 5 | import kotlinx.coroutines.awaitAll 6 | import kotlinx.coroutines.runBlocking 7 | import org.archguard.scanner.core.sourcecode.LanguageSourceCodeAnalyser 8 | import org.archguard.scanner.core.sourcecode.SourceCodeContext 9 | import java.io.File 10 | 11 | class GoAnalyser(override val context: SourceCodeContext) : LanguageSourceCodeAnalyser { 12 | private val client = context.client 13 | private val impl = chapi.ast.goast.GoAnalyser() 14 | 15 | override fun analyse(): List = runBlocking { 16 | getFilesByPath(context.path) { 17 | it.absolutePath.endsWith(".go") 18 | } 19 | .map { async { analysisByFile(it) } }.awaitAll() 20 | .flatten() 21 | .also { client.saveDataStructure(it) } 22 | } 23 | 24 | private fun analysisByFile(file: File): List { 25 | val codeContainer = impl.analysis(file.readContent(), file.name) 26 | 27 | return codeContainer.DataStructures.map { 28 | it.apply { 29 | it.Imports = codeContainer.Imports 30 | it.FilePath = file.absolutePath 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /analyser_sourcecode/lang_golang/src/test/kotlin/org/archguard/scanner/analyser/GoAnalyserTest.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.analyser 2 | 3 | import io.mockk.clearAllMocks 4 | import io.mockk.every 5 | import io.mockk.just 6 | import io.mockk.mockk 7 | import io.mockk.runs 8 | import io.mockk.verify 9 | import org.archguard.scanner.core.client.ArchGuardClient 10 | import org.archguard.scanner.core.sourcecode.SourceCodeContext 11 | import org.junit.jupiter.api.AfterEach 12 | import org.junit.jupiter.api.Assertions 13 | import org.junit.jupiter.api.BeforeEach 14 | import org.junit.jupiter.api.Test 15 | 16 | internal class GoAnalyserTest { 17 | private val mockClient = mockk { 18 | every { saveDataStructure(any()) } just runs 19 | } 20 | private val mockContext = mockk { 21 | every { client } returns mockClient 22 | } 23 | 24 | @AfterEach 25 | internal fun tearDown() { 26 | verify { mockClient.saveDataStructure(any()) } 27 | } 28 | 29 | @Test 30 | fun `should return nodes of the sample code file`() { 31 | every { mockContext.path } returns this.javaClass.classLoader.getResource("go").path 32 | 33 | val result = GoAnalyser(mockContext).analyse() 34 | 35 | Assertions.assertEquals(result.size, 1) 36 | assert(result[0].FilePath.contains("hello.go")) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /analyser_sourcecode/lang_golang/src/test/resources/go/hello.go: -------------------------------------------------------------------------------- 1 | package tbs 2 | 3 | import "testing" 4 | 5 | func TestTbsApp_EmptyTest(t *testing.T) { 6 | 7 | } 8 | -------------------------------------------------------------------------------- /analyser_sourcecode/lang_java/.gitignore: -------------------------------------------------------------------------------- 1 | structs_*.json 2 | -------------------------------------------------------------------------------- /analyser_sourcecode/lang_java/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | application 3 | kotlin("jvm") version "1.6.10" 4 | kotlin("plugin.serialization") version "1.6.10" 5 | id("com.github.johnrengelman.shadow") version "7.0.0" 6 | } 7 | 8 | dependencies { 9 | api(project(":scanner_core")) 10 | 11 | implementation("com.phodal.chapi:chapi-ast-java:1.5.6") { 12 | // around 10mb, only documents files, exclude (reuse in cli?) 13 | exclude(group = "com.ibm.icu", module = "icu4j") 14 | } 15 | 16 | testImplementation("io.mockk:mockk:1.12.3") 17 | testImplementation("org.assertj:assertj-core:3.22.0") 18 | } 19 | 20 | application { 21 | mainClass.set("org.archguard.scanner.core.AnalyserKt") 22 | } 23 | 24 | tasks { 25 | shadowJar { 26 | dependencies { 27 | exclude(dependency("org.jetbrains.kotlin:.*:.*")) 28 | exclude(dependency("org.jetbrains.kotlinx:.*:.*")) 29 | } 30 | minimize() 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /analyser_sourcecode/lang_java/src/test/resources/spring/DemoController.java: -------------------------------------------------------------------------------- 1 | package com.macro.mall.demo.controller; 2 | 3 | import com.macro.mall.common.api.CommonPage; 4 | import com.macro.mall.common.api.CommonResult; 5 | import com.macro.mall.demo.dto.PmsBrandDto; 6 | import com.macro.mall.demo.service.DemoService; 7 | import com.macro.mall.model.PmsBrand; 8 | import io.swagger.annotations.Api; 9 | import io.swagger.annotations.ApiOperation; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.stereotype.Controller; 12 | import org.springframework.validation.annotation.Validated; 13 | import org.springframework.web.bind.annotation.*; 14 | 15 | /** 16 | * 品牌管理示例controller 17 | * Created by macro on 2019/4/8. 18 | */ 19 | @Api(tags = "DemoController", description = "品牌管理示例接口") 20 | @Controller 21 | public class DemoController { 22 | @Autowired 23 | private DemoService demoService; 24 | 25 | private static final org.slf4j.Logger LOGGER = org.slf4j.LoggerFactory.getLogger(com.macro.mall.demo.controller.DemoController.class); 26 | 27 | @RequestMapping(value = "/brand/listAll", method = RequestMethod.GET) 28 | public CommonResult> getBrandList() { 29 | return CommonResult.success(demoService.listAllBrand()); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /analyser_sourcecode/lang_java/src/test/resources/spring/HelloController.java: -------------------------------------------------------------------------------- 1 | package com.example.springboot; 2 | 3 | import org.springframework.web.bind.annotation.GetMapping; 4 | import org.springframework.web.bind.annotation.RestController; 5 | 6 | @RestController 7 | @RequestMapping 8 | public class HelloController { 9 | 10 | @GetMapping("/") 11 | public String index() { 12 | return "Greetings from Spring Boot!"; 13 | } 14 | 15 | } -------------------------------------------------------------------------------- /analyser_sourcecode/lang_java/src/test/resources/spring/NormalController.java: -------------------------------------------------------------------------------- 1 | package com.example.springboot; 2 | 3 | import org.springframework.web.bind.annotation.GetMapping; 4 | import org.springframework.web.bind.annotation.RestController; 5 | 6 | @RestController 7 | @RequestMapping("/api/sub") 8 | public class HelloController { 9 | 10 | @GetMapping("/overview") 11 | public String index() { 12 | return "Greetings from Spring Boot!"; 13 | } 14 | 15 | } -------------------------------------------------------------------------------- /analyser_sourcecode/lang_java/src/test/resources/spring/SubController.java: -------------------------------------------------------------------------------- 1 | package com.example.springboot; 2 | 3 | import org.springframework.web.bind.annotation.GetMapping; 4 | import org.springframework.web.bind.annotation.RestController; 5 | 6 | @RestController 7 | @RequestMapping("/api/sub") 8 | public class HelloController { 9 | 10 | @GetMapping 11 | public String index() { 12 | return "Greetings from Spring Boot!"; 13 | } 14 | 15 | } -------------------------------------------------------------------------------- /analyser_sourcecode/lang_kotlin/.gitignore: -------------------------------------------------------------------------------- 1 | structs_*.json 2 | -------------------------------------------------------------------------------- /analyser_sourcecode/lang_kotlin/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | application 3 | kotlin("jvm") version "1.6.10" 4 | kotlin("plugin.serialization") version "1.6.10" 5 | id("com.github.johnrengelman.shadow") version "7.0.0" 6 | } 7 | 8 | dependencies { 9 | api(project(":scanner_core")) 10 | 11 | implementation("com.phodal.chapi:chapi-ast-kotlin:1.5.6") { 12 | // around 10mb, only documents files, exclude (reuse in cli?) 13 | exclude(group = "com.ibm.icu", module = "icu4j") 14 | } 15 | 16 | testImplementation("io.mockk:mockk:1.12.3") 17 | testImplementation("org.assertj:assertj-core:3.22.0") 18 | } 19 | 20 | application { 21 | mainClass.set("org.archguard.scanner.core.AnalyserKt") 22 | } 23 | 24 | tasks { 25 | shadowJar { 26 | dependencies { 27 | exclude(dependency("org.jetbrains.kotlin:.*:.*")) 28 | exclude(dependency("org.jetbrains.kotlinx:.*:.*")) 29 | } 30 | minimize() 31 | } 32 | } 33 | 34 | -------------------------------------------------------------------------------- /analyser_sourcecode/lang_kotlin/src/main/kotlin/org/archguard/scanner/analyser/KotlinAnalyser.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.analyser 2 | 3 | import chapi.ast.kotlinast.AnalysisMode 4 | import chapi.domain.core.CodeDataStruct 5 | import kotlinx.coroutines.async 6 | import kotlinx.coroutines.awaitAll 7 | import kotlinx.coroutines.runBlocking 8 | import org.archguard.scanner.core.sourcecode.LanguageSourceCodeAnalyser 9 | import org.archguard.scanner.core.sourcecode.SourceCodeContext 10 | import java.io.File 11 | 12 | class KotlinAnalyser(override val context: SourceCodeContext) : LanguageSourceCodeAnalyser { 13 | private val client = context.client 14 | private val impl = chapi.ast.kotlinast.KotlinAnalyser() 15 | 16 | override fun analyse(): List = runBlocking { 17 | getFilesByPath(context.path) { 18 | it.absolutePath.endsWith(".kt") || it.absolutePath.endsWith(".kts") 19 | } 20 | .map { async { analysisByFile(it) } }.awaitAll() 21 | .flatten() 22 | .also { client.saveDataStructure(it) } 23 | } 24 | 25 | private fun analysisByFile(file: File): List { 26 | return impl.analysis(file.readContent(), file.name, AnalysisMode.Full).DataStructures 27 | .map { it.apply { it.FilePath = file.absolutePath } } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /analyser_sourcecode/lang_kotlin/src/test/resources/kotlin/Hello.kt: -------------------------------------------------------------------------------- 1 | class Hello { 2 | fun sayHello() { 3 | println("Hello Kotlin!") 4 | } 5 | } 6 | 7 | fun main() { 8 | Hello().sayHello() 9 | } 10 | -------------------------------------------------------------------------------- /analyser_sourcecode/lang_kotlin/src/test/resources/spring/QualityGateClientImpl.kt: -------------------------------------------------------------------------------- 1 | package kotlin 2 | 3 | import com.thoughtworks.archguard.report.domain.qualitygate.CouplingQualityGate 4 | import com.thoughtworks.archguard.report.domain.qualitygate.QualityGateClient 5 | import org.springframework.beans.factory.annotation.Value 6 | import org.springframework.stereotype.Component 7 | import org.springframework.web.client.RestTemplate 8 | 9 | 10 | @Component 11 | class QualityGateClientImpl(@Value("\${api.host}") val baseUrl: String) : QualityGateClient { 12 | override fun getQualityGate(qualityGateName: String): CouplingQualityGate { 13 | val couplingQualityGate = RestTemplate().getForObject("$baseUrl/api/quality-gate-profile/$qualityGateName", CouplingQualityGate::class.java) 14 | return couplingQualityGate ?: CouplingQualityGate(null, qualityGateName, emptyList(), null, null) 15 | } 16 | } -------------------------------------------------------------------------------- /analyser_sourcecode/lang_python/.gitignore: -------------------------------------------------------------------------------- 1 | structs_*.json 2 | -------------------------------------------------------------------------------- /analyser_sourcecode/lang_python/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | application 3 | kotlin("jvm") version "1.6.10" 4 | kotlin("plugin.serialization") version "1.6.10" 5 | id("com.github.johnrengelman.shadow") version "7.0.0" 6 | } 7 | 8 | dependencies { 9 | api(project(":scanner_core")) 10 | 11 | implementation("com.phodal.chapi:chapi-ast-python:1.5.6") { 12 | // around 10mb, only documents files, exclude (reuse in cli?) 13 | exclude(group = "com.ibm.icu", module = "icu4j") 14 | } 15 | 16 | testImplementation("io.mockk:mockk:1.12.3") 17 | testImplementation("org.assertj:assertj-core:3.22.0") 18 | } 19 | 20 | application { 21 | mainClass.set("org.archguard.scanner.core.AnalyserKt") 22 | } 23 | 24 | tasks { 25 | shadowJar { 26 | dependencies { 27 | exclude(dependency("org.jetbrains.kotlin:.*:.*")) 28 | exclude(dependency("org.jetbrains.kotlinx:.*:.*")) 29 | } 30 | minimize() 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /analyser_sourcecode/lang_python/src/main/kotlin/org/archguard/scanner/analyser/PythonAnalyser.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.analyser 2 | 3 | import chapi.domain.core.CodeDataStruct 4 | import kotlinx.coroutines.async 5 | import kotlinx.coroutines.awaitAll 6 | import kotlinx.coroutines.runBlocking 7 | import org.archguard.scanner.core.sourcecode.LanguageSourceCodeAnalyser 8 | import org.archguard.scanner.core.sourcecode.SourceCodeContext 9 | import java.io.File 10 | 11 | class PythonAnalyser(override val context: SourceCodeContext) : LanguageSourceCodeAnalyser { 12 | private val client = context.client 13 | private val impl = chapi.ast.pythonast.PythonAnalyser() 14 | 15 | override fun analyse(): List = runBlocking { 16 | getFilesByPath(context.path) { 17 | it.absolutePath.endsWith(".py") 18 | } 19 | .map { async { analysisByFile(it) } }.awaitAll() 20 | .flatten() 21 | .also { client.saveDataStructure(it) } 22 | } 23 | 24 | private fun analysisByFile(file: File): List { 25 | val codeContainer = impl.analysis(file.readContent(), file.name) 26 | 27 | return codeContainer.DataStructures.map { 28 | it.apply { 29 | it.Imports = codeContainer.Imports 30 | it.FilePath = file.absolutePath 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /analyser_sourcecode/lang_python/src/test/kotlin/org/archguard/scanner/analyser/PythonAnalyserTest.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.analyser 2 | 3 | import io.mockk.clearAllMocks 4 | import io.mockk.every 5 | import io.mockk.just 6 | import io.mockk.mockk 7 | import io.mockk.runs 8 | import io.mockk.verify 9 | import org.archguard.scanner.core.client.ArchGuardClient 10 | import org.archguard.scanner.core.sourcecode.SourceCodeContext 11 | import org.junit.jupiter.api.AfterEach 12 | import org.junit.jupiter.api.Assertions 13 | import org.junit.jupiter.api.BeforeEach 14 | import org.junit.jupiter.api.Test 15 | 16 | internal class PythonAnalyserTest { 17 | private val mockClient = mockk { 18 | every { saveDataStructure(any()) } just runs 19 | } 20 | private val mockContext = mockk { 21 | every { client } returns mockClient 22 | } 23 | 24 | @AfterEach 25 | internal fun tearDown() { 26 | verify { mockClient.saveDataStructure(any()) } 27 | } 28 | 29 | @Test 30 | fun `should return nodes of the sample code file`() { 31 | every { mockContext.path } returns this.javaClass.classLoader.getResource("py").path 32 | 33 | val result = PythonAnalyser(mockContext).analyse() 34 | 35 | Assertions.assertEquals(result.size, 2) 36 | Assertions.assertEquals(result[0].NodeName, "foo") 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /analyser_sourcecode/lang_python/src/test/resources/py/class.py: -------------------------------------------------------------------------------- 1 | class foo: pass 2 | 3 | class baz(foo): 4 | pass 5 | -------------------------------------------------------------------------------- /analyser_sourcecode/lang_scala/.gitignore: -------------------------------------------------------------------------------- 1 | structs_*.json 2 | -------------------------------------------------------------------------------- /analyser_sourcecode/lang_scala/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | application 3 | kotlin("jvm") version "1.6.10" 4 | kotlin("plugin.serialization") version "1.6.10" 5 | id("com.github.johnrengelman.shadow") version "7.0.0" 6 | } 7 | 8 | dependencies { 9 | api(project(":scanner_core")) 10 | 11 | implementation("com.phodal.chapi:chapi-ast-scala:1.5.6") { 12 | // around 10mb, only documents files, exclude (reuse in cli?) 13 | exclude(group = "com.ibm.icu", module = "icu4j") 14 | } 15 | 16 | testImplementation("io.mockk:mockk:1.12.3") 17 | testImplementation("org.assertj:assertj-core:3.22.0") 18 | } 19 | 20 | application { 21 | mainClass.set("org.archguard.scanner.core.AnalyserKt") 22 | } 23 | 24 | tasks { 25 | shadowJar { 26 | dependencies { 27 | exclude(dependency("org.jetbrains.kotlin:.*:.*")) 28 | exclude(dependency("org.jetbrains.kotlinx:.*:.*")) 29 | } 30 | minimize() 31 | } 32 | } 33 | 34 | -------------------------------------------------------------------------------- /analyser_sourcecode/lang_scala/src/main/kotlin/org/archguard/scanner/analyser/ScalaAnalyser.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.analyser 2 | 3 | import chapi.domain.core.CodeDataStruct 4 | import kotlinx.coroutines.async 5 | import kotlinx.coroutines.awaitAll 6 | import kotlinx.coroutines.runBlocking 7 | import org.archguard.scanner.core.sourcecode.LanguageSourceCodeAnalyser 8 | import org.archguard.scanner.core.sourcecode.SourceCodeContext 9 | import java.io.File 10 | 11 | class ScalaAnalyser(override val context: SourceCodeContext) : LanguageSourceCodeAnalyser { 12 | private val client = context.client 13 | private val impl = chapi.ast.scalaast.ScalaAnalyser() 14 | 15 | override fun analyse(): List = runBlocking { 16 | getFilesByPath(context.path) { 17 | it.absolutePath.endsWith(".scala") 18 | } 19 | .map { async { analysisByFile(it) } }.awaitAll() 20 | .flatten() 21 | .also { client.saveDataStructure(it) } 22 | } 23 | 24 | private fun analysisByFile(file: File): List { 25 | val codeContainer = impl.analysis(file.readContent(), file.name) 26 | 27 | return codeContainer.DataStructures.map { 28 | it.apply { 29 | it.Imports = codeContainer.Imports 30 | it.FilePath = file.absolutePath 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /analyser_sourcecode/lang_scala/src/test/kotlin/org/archguard/scanner/analyser/ScalaAnalyserTest.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.analyser 2 | 3 | import io.mockk.clearAllMocks 4 | import io.mockk.every 5 | import io.mockk.just 6 | import io.mockk.mockk 7 | import io.mockk.runs 8 | import io.mockk.verify 9 | import org.archguard.scanner.core.client.ArchGuardClient 10 | import org.archguard.scanner.core.sourcecode.SourceCodeContext 11 | import org.junit.jupiter.api.AfterEach 12 | import org.junit.jupiter.api.Assertions 13 | import org.junit.jupiter.api.BeforeEach 14 | import org.junit.jupiter.api.Test 15 | 16 | internal class ScalaAnalyserTest { 17 | private val mockClient = mockk { 18 | every { saveDataStructure(any()) } just runs 19 | } 20 | private val mockContext = mockk { 21 | every { client } returns mockClient 22 | } 23 | 24 | @AfterEach 25 | internal fun tearDown() { 26 | verify { mockClient.saveDataStructure(any()) } 27 | } 28 | 29 | @Test 30 | fun `should return nodes of the sample code file`() { 31 | every { mockContext.path } returns this.javaClass.classLoader.getResource("scala").path 32 | 33 | val result = ScalaAnalyser(mockContext).analyse() 34 | 35 | Assertions.assertEquals(result.size, 1) 36 | Assertions.assertEquals(result[0].NodeName, "HelloWorld") 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /analyser_sourcecode/lang_scala/src/test/resources/scala/class.scala: -------------------------------------------------------------------------------- 1 | object HelloWorld { 2 | def main(args: Array[String]): Unit = { 3 | println("Hello, world!") 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /analyser_sourcecode/lang_typescript/.gitignore: -------------------------------------------------------------------------------- 1 | structs_*.json 2 | -------------------------------------------------------------------------------- /analyser_sourcecode/lang_typescript/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | application 3 | kotlin("jvm") version "1.6.10" 4 | kotlin("plugin.serialization") version "1.6.10" 5 | id("com.github.johnrengelman.shadow") version "7.0.0" 6 | } 7 | 8 | dependencies { 9 | api(project(":scanner_core")) 10 | 11 | implementation("com.phodal.chapi:chapi-ast-typescript:1.5.6") { 12 | // around 10mb, only documents files, exclude (reuse in cli?) 13 | exclude(group = "com.ibm.icu", module = "icu4j") 14 | } 15 | 16 | testImplementation("io.mockk:mockk:1.12.3") 17 | testImplementation("org.assertj:assertj-core:3.22.0") 18 | } 19 | 20 | application { 21 | mainClass.set("org.archguard.scanner.core.AnalyserKt") 22 | } 23 | 24 | tasks { 25 | shadowJar { 26 | dependencies { 27 | exclude(dependency("org.jetbrains.kotlin:.*:.*")) 28 | exclude(dependency("org.jetbrains.kotlinx:.*:.*")) 29 | } 30 | minimize() 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /analyser_sourcecode/lang_typescript/src/test/resources/ts/api-adapter/src/api/module/profile.ts: -------------------------------------------------------------------------------- 1 | import axios from "../axios"; 2 | import { Profile } from '@/pages/quality-gate-profile'; 3 | const baseURL = '/api' 4 | 5 | export function queryAllQualityGateProfile() { 6 | return axios({ 7 | baseURL, 8 | url: '/quality-gate-profile', 9 | method: "GET" 10 | }); 11 | } 12 | 13 | export function createQualityGateProfile(params: Profile) { 14 | return axios({ 15 | baseURL, 16 | url: '/quality-gate-profile', 17 | method: "POST", 18 | data: params, 19 | }); 20 | } 21 | 22 | export function updateQualityGateProfile(id: number, params: Profile) { 23 | return axios({ 24 | baseURL, 25 | url: `/quality-gate-profile/${id}`, 26 | method: "PUT", 27 | data: params, 28 | }); 29 | } 30 | 31 | export function deleteQualityGateProfile(id: number) { 32 | return axios({ 33 | baseURL, 34 | url: `/quality-gate-profile/${id}`, 35 | method: "DELETE", 36 | }); 37 | } 38 | -------------------------------------------------------------------------------- /analyser_sourcecode/lang_typescript/src/test/resources/ts/api-adapter/src/global-cache-state/useQualityGate.ts: -------------------------------------------------------------------------------- 1 | import createCacheState from "@/utils/utils"; 2 | import { queryAllQualityGateProfile } from "@/api/module/profile"; 3 | 4 | const useQualityGate = createCacheState(queryAllQualityGateProfile, []); 5 | export default useQualityGate; 6 | -------------------------------------------------------------------------------- /analyser_sourcecode/lang_typescript/src/test/resources/ts/apicall/src/api/addition/config.ts: -------------------------------------------------------------------------------- 1 | export const baseURL = '/api' 2 | -------------------------------------------------------------------------------- /analyser_sourcecode/lang_typescript/src/test/resources/ts/apicall/src/api/addition/evaluations.ts: -------------------------------------------------------------------------------- 1 | import { baseURL } from './config'; 2 | // @ts-ignore 3 | import { SystemEvaluationHistoryType } from "../../models/system-evaluation"; 4 | // @ts-ignore 5 | import axios from "../axios"; 6 | 7 | export function queryEvaluationList() { 8 | return axios({ 9 | baseURL, 10 | url: '/evaluations', 11 | method: "GET", 12 | }); 13 | } 14 | 15 | export function queryEvaluation(id: string) { 16 | return axios({ 17 | baseURL, 18 | url: `/evaluations/${id}`, 19 | method: "GET", 20 | }); 21 | } 22 | 23 | export function queryEvaluationDetails(id: string) { 24 | return axios({ 25 | baseURL, 26 | url: `/evaluation-details/${id}`, 27 | method: "GET", 28 | }); 29 | } 30 | -------------------------------------------------------------------------------- /analyser_sourcecode/lang_typescript/src/test/resources/ts/apicall/src/api/addition/systemInfo.ts: -------------------------------------------------------------------------------- 1 | import axios from "../axios"; 2 | import { baseURL } from "./config"; 3 | const systemInfoApi = "/system-info"; 4 | 5 | export interface SystemInfo { 6 | id: number; 7 | systemName: string; 8 | repo: string[]; 9 | repoType: "GIT" | "SVN"; 10 | username: string; 11 | password: string; 12 | sql: string; 13 | scanned: "NONE" | "SCANNING" | "SCANNED" | "FAILED"; 14 | updatedTime: number; 15 | badSmellThresholdSuiteId: number; 16 | branch: string; 17 | } 18 | 19 | export function querySystemInfo() { 20 | return axios({ 21 | baseURL, 22 | url: systemInfoApi, 23 | method: "GET", 24 | }); 25 | } 26 | 27 | export function updateSystemInfo(parameter: any) { 28 | return axios({ 29 | baseURL, 30 | url: systemInfoApi, 31 | method: "PUT", 32 | data: parameter, 33 | }); 34 | } 35 | 36 | export function createSystemInfo(parameter: any) { 37 | return axios({ 38 | baseURL, 39 | url: systemInfoApi, 40 | method: "POST", 41 | data: parameter, 42 | }); 43 | } 44 | 45 | export function deleteSystem(systemId: number) { 46 | return axios({ 47 | baseURL, 48 | url: `${systemInfoApi}/${systemId}`, 49 | method: "DELETE", 50 | }); 51 | } 52 | -------------------------------------------------------------------------------- /analyser_sourcecode/lang_typescript/src/test/resources/ts/hello-world.ts: -------------------------------------------------------------------------------- 1 | class Greeter { 2 | greeting: string; 3 | constructor(message: string) { 4 | this.greeting = message; 5 | } 6 | greet() { 7 | return "Hello, " + this.greeting; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /analyser_sourcecode/lang_typescript/src/test/resources/ts/interface-error/src/api/module/dependenceConfig.ts: -------------------------------------------------------------------------------- 1 | import { baseURL } from './config'; 2 | import axios from "../axios"; 3 | 4 | export function queryConfig() { 5 | return axios({ 6 | baseURL, 7 | url: '/configures', 8 | method: "GET" 9 | }); 10 | } 11 | 12 | export function updateConfig(type: string, parameter: any) { 13 | return axios({ 14 | baseURL, 15 | url: `/configures/types/${type}`, 16 | method: 'POST', 17 | data: parameter 18 | }) 19 | } 20 | -------------------------------------------------------------------------------- /analyser_sourcecode/lang_typescript/src/test/resources/ts/js-umi-request/src/SystemConfig.jsx: -------------------------------------------------------------------------------- 1 | import { querySystemInfo } from './system-info'; 2 | 3 | function TopicSetting(props) { 4 | useEffect(() => { 5 | querySystemInfo({ project: 'chapi'}).then((res) => { 6 | return res; 7 | }); 8 | }, []); 9 | 10 | return (); 11 | } 12 | -------------------------------------------------------------------------------- /analyser_sourcecode/lang_typescript/src/test/resources/ts/js-umi-request/src/system-info.js: -------------------------------------------------------------------------------- 1 | import request from 'umi-request'; 2 | 3 | export const querySystemInfo = (data) => { 4 | return request(`/api/system-info`, { 5 | method: 'GET', 6 | }); 7 | }; 8 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | kotlin.code.style=official 2 | kotlin.mpp.stability.nowarn=true 3 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/archguard/scanner/c7723b67ef980af88c078da28c9d2927147daf7a/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /legacy/common-code-repository/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | base 3 | java 4 | kotlin("jvm") version "1.6.10" 5 | kotlin("plugin.serialization") version "1.6.10" 6 | } 7 | 8 | dependencies { 9 | api(project(":scanner_core")) 10 | 11 | implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.2") 12 | 13 | implementation("io.netty:netty-all:4.1.42.Final") 14 | 15 | implementation("com.zaxxer:HikariCP:5.0.1") 16 | implementation("org.jdbi:jdbi3-core:3.8.2") 17 | implementation("mysql:mysql-connector-java:8.0.28") 18 | 19 | implementation("com.phodal.chapi:chapi-domain:1.5.6") 20 | 21 | // mock for logger 22 | implementation("io.github.hakky54:logcaptor:2.7.9") 23 | testImplementation("org.assertj:assertj-core:3.22.0") 24 | } 25 | -------------------------------------------------------------------------------- /legacy/common-code-repository/src/main/java/com/thoughtworks/archguard/infrastructure/IBatch.java: -------------------------------------------------------------------------------- 1 | package com.thoughtworks.archguard.infrastructure; 2 | 3 | import java.util.Map; 4 | import java.util.Optional; 5 | import java.util.Set; 6 | 7 | public interface IBatch { 8 | 9 | void add(String table, Map values); 10 | 11 | void update(String table, Map keys, Map values); 12 | 13 | void execute(); 14 | 15 | Optional findId(String table, Map keys); 16 | 17 | void close(); 18 | 19 | Set getModuleSet(); 20 | } 21 | -------------------------------------------------------------------------------- /legacy/common-code-repository/src/main/java/com/thoughtworks/archguard/infrastructure/task/ShutdownHook.java: -------------------------------------------------------------------------------- 1 | package com.thoughtworks.archguard.infrastructure.task; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | public class ShutdownHook { 7 | private static final Logger logger = LoggerFactory.getLogger(ShutdownHook.class); 8 | 9 | public static void register(long startTime) { 10 | new ShutdownHook(startTime); 11 | } 12 | 13 | public ShutdownHook(long start) { 14 | Thread t = new Thread(() -> 15 | logger.info("总共运行时间为:{}s", (System.currentTimeMillis() - start) / 1000)); 16 | Runtime.getRuntime().addShutdownHook(t); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /legacy/common-code-repository/src/main/java/com/thoughtworks/archguard/infrastructure/task/SqlExecuteRunnable.java: -------------------------------------------------------------------------------- 1 | package com.thoughtworks.archguard.infrastructure.task; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import java.util.Objects; 7 | import java.util.concurrent.Phaser; 8 | 9 | public class SqlExecuteRunnable implements Runnable { 10 | 11 | private final Logger logger = LoggerFactory.getLogger(getClass()); 12 | private final String name; 13 | private final Runnable task; 14 | private Phaser phaser; 15 | 16 | public SqlExecuteRunnable(String name, Phaser phaser, Runnable task) { 17 | this.name = name; 18 | this.task = task; 19 | this.phaser = phaser; 20 | this.phaser.register(); 21 | } 22 | 23 | public SqlExecuteRunnable(String name, Runnable task) { 24 | this.name = name; 25 | this.task = task; 26 | } 27 | 28 | @Override 29 | public void run() { 30 | logger.info("thread-{} is running", this.name); 31 | task.run(); 32 | if (!Objects.isNull(this.phaser)) { 33 | this.phaser.arriveAndDeregister(); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /legacy/common-code-repository/src/main/java/com/thoughtworks/archguard/infrastructure/task/SqlExecuteThreadPool.java: -------------------------------------------------------------------------------- 1 | package com.thoughtworks.archguard.infrastructure.task; 2 | 3 | import java.util.concurrent.ExecutorService; 4 | import java.util.concurrent.Executors; 5 | 6 | public class SqlExecuteThreadPool { 7 | private static final SqlExecuteThreadPool instance = new SqlExecuteThreadPool(); 8 | private final ExecutorService pool = Executors.newFixedThreadPool(5); 9 | 10 | public static void execute(Runnable task) { 11 | instance.pool.execute(task); 12 | } 13 | 14 | public static void close() { 15 | instance.pool.shutdown(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /legacy/common-code-repository/src/main/java/com/thoughtworks/archguard/infrastructure/utils/UpdateRecord.java: -------------------------------------------------------------------------------- 1 | package com.thoughtworks.archguard.infrastructure.utils; 2 | 3 | import java.util.Map; 4 | 5 | public class UpdateRecord { 6 | private final Map keys; 7 | private final Map values; 8 | 9 | public UpdateRecord(Map keys, Map values) { 10 | this.keys = keys; 11 | this.values = values; 12 | } 13 | 14 | public Map getKeys() { 15 | return keys; 16 | } 17 | 18 | public Map getValues() { 19 | return values; 20 | } 21 | 22 | public static UpdateRecord of(UpdateRecordKey key, UpdateRecordValue value) { 23 | return new UpdateRecord(key.getKeys(), value.getValues()); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /legacy/common-code-repository/src/main/java/com/thoughtworks/archguard/infrastructure/utils/UpdateRecordKey.java: -------------------------------------------------------------------------------- 1 | package com.thoughtworks.archguard.infrastructure.utils; 2 | 3 | import java.util.Map; 4 | import java.util.Objects; 5 | 6 | public class UpdateRecordKey { 7 | private Map keys; 8 | 9 | public UpdateRecordKey(Map keys) { 10 | this.keys = keys; 11 | } 12 | 13 | public static UpdateRecordKey of(Map keys) { 14 | return new UpdateRecordKey(keys); 15 | } 16 | 17 | public Map getKeys() { 18 | return keys; 19 | } 20 | 21 | @Override 22 | public boolean equals(Object o) { 23 | UpdateRecordKey that = (UpdateRecordKey) o; 24 | return this.keys.equals(that.keys); 25 | } 26 | 27 | @Override 28 | public int hashCode() { 29 | return Objects.hash(keys); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /legacy/common-code-repository/src/main/java/com/thoughtworks/archguard/infrastructure/utils/UpdateRecordSet.java: -------------------------------------------------------------------------------- 1 | package com.thoughtworks.archguard.infrastructure.utils; 2 | 3 | import java.util.Map; 4 | import java.util.concurrent.ConcurrentHashMap; 5 | import java.util.function.BiConsumer; 6 | 7 | public class UpdateRecordSet { 8 | Map> updateStore = new ConcurrentHashMap<>(); 9 | 10 | public void put(String table, Map keys, Map values) { 11 | if (!updateStore.containsKey(table)) { 12 | updateStore.put(table, new ConcurrentHashMap<>()); 13 | } 14 | 15 | UpdateRecordKey k = UpdateRecordKey.of(keys); 16 | UpdateRecordValue v = UpdateRecordValue.of(values); 17 | 18 | if (updateStore.get(table).containsKey(k)) { 19 | updateStore.get(table).get(k).addValues(values); 20 | } else { 21 | updateStore.get(table).put(k, v); 22 | } 23 | } 24 | 25 | public void processEachRecord(BiConsumer consumer) { 26 | updateStore.forEach((table, recordMap) -> { 27 | recordMap.forEach((key, value) -> { 28 | consumer.accept(table, UpdateRecord.of(key, value)); 29 | }); 30 | }); 31 | } 32 | 33 | public void clear() { 34 | updateStore.clear(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /legacy/common-code-repository/src/main/java/com/thoughtworks/archguard/infrastructure/utils/UpdateRecordValue.java: -------------------------------------------------------------------------------- 1 | package com.thoughtworks.archguard.infrastructure.utils; 2 | 3 | import java.util.Map; 4 | 5 | public class UpdateRecordValue { 6 | private Map values; 7 | 8 | public Map getValues() { 9 | return values; 10 | } 11 | 12 | public UpdateRecordValue(Map values) { 13 | this.values = values; 14 | } 15 | 16 | public void addValues(Map values) { 17 | values.forEach((key, value) -> 18 | // 覆盖 19 | this.values.put(key, value)); 20 | } 21 | 22 | public static UpdateRecordValue of(Map values) { 23 | return new UpdateRecordValue(values); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /legacy/common-code-repository/src/main/kotlin/org/archguard/scanner/common/RepositoryHelper.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.common 2 | 3 | import java.text.SimpleDateFormat 4 | import java.util.* 5 | 6 | object RepositoryHelper { 7 | fun generateId(): String { 8 | return UUID.randomUUID().toString() 9 | } 10 | 11 | val currentTime: String 12 | get() { 13 | val dt = Date() 14 | val sdf = SimpleDateFormat("yyyy-MM-dd HH:mm:ss") 15 | return sdf.format(dt) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /legacy/common-code-repository/src/test/java/com/thoughtworks/archguard/infrastructure/utils/UpdateRecordKeyTest.java: -------------------------------------------------------------------------------- 1 | package com.thoughtworks.archguard.infrastructure.utils; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertTrue; 4 | 5 | class UpdateRecordKeyTest { 6 | @org.junit.jupiter.api.Test 7 | public void testEqual() { 8 | java.util.Map keyA = new java.util.concurrent.ConcurrentHashMap<>(); 9 | java.util.Map keyB = new java.util.concurrent.ConcurrentHashMap<>(); 10 | keyA.put("id-for-key", "id-for-value"); 11 | keyB.put("id-for-key", "id-for-value"); 12 | UpdateRecordKey a = UpdateRecordKey.of(keyA); 13 | UpdateRecordKey b = UpdateRecordKey.of(keyB); 14 | 15 | assertTrue(a.equals(b)); 16 | } 17 | 18 | @org.junit.jupiter.api.Test 19 | public void testMapKey() { 20 | java.util.Map map = new java.util.concurrent.ConcurrentHashMap<>(); 21 | java.util.Map keyA = new java.util.concurrent.ConcurrentHashMap<>(); 22 | java.util.Map keyB = new java.util.concurrent.ConcurrentHashMap<>(); 23 | keyA.put("id-for-key", "id-for-value"); 24 | keyB.put("id-for-key", "id-for-value"); 25 | UpdateRecordKey a = UpdateRecordKey.of(keyA); 26 | UpdateRecordKey b = UpdateRecordKey.of(keyB); 27 | 28 | map.put(a, "value-for-key-a"); 29 | assertTrue(map.containsKey(b)); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /legacy/scan_bytecode/build.gradle.kts: -------------------------------------------------------------------------------- 1 | group = "org.archguard.scanner" 2 | 3 | plugins { 4 | id("application") 5 | kotlin("jvm") version "1.6.10" 6 | id("com.github.johnrengelman.shadow") version "7.0.0" 7 | 8 | kotlin("plugin.serialization") version "1.6.10" 9 | } 10 | 11 | dependencies { 12 | api(project(":common_code_repository")) 13 | api(project(":analyser_sourcecode:feat_apicalls")) 14 | 15 | implementation("io.netty:netty-all:4.1.42.Final") 16 | 17 | implementation("com.github.ajalt.clikt:clikt:3.4.0") 18 | 19 | implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.2") 20 | 21 | implementation("org.jdbi:jdbi3-core:3.8.2") 22 | 23 | implementation("com.phodal.chapi:chapi-domain:1.5.6") 24 | 25 | implementation("org.ow2.asm:asm:9.2") 26 | implementation("org.ow2.asm:asm-util:9.2") 27 | } 28 | 29 | application { 30 | mainClass.set("org.archguard.scanner.bytecode.RunnerKt") 31 | } 32 | 33 | tasks{ 34 | shadowJar { 35 | manifest { 36 | attributes(Pair("Main-Class", "org.archguard.scanner.bytecode.RunnerKt")) 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /legacy/scan_bytecode/src/main/kotlin/org/archguard/scanner/bytecode/ImportCollector.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.bytecode 2 | 3 | class ImportCollector { 4 | private val JAVA_LANG_PACKAGE = "java." 5 | private val KOTLIN_LANG_PACKAGE = "kotlin." 6 | 7 | private val DEFAULT_TYPE_NAMES = arrayOf( 8 | "byte", 9 | "char", 10 | "double", 11 | "float", 12 | "int", 13 | "long", 14 | "short", 15 | "boolean" 16 | ) 17 | 18 | private var mapSimpleNames: MutableMap = mutableMapOf() 19 | 20 | fun splitPackageAndClassName(fullName: String): Pair { 21 | val lastDot = fullName.lastIndexOf('.') 22 | var packageName = fullName 23 | var className = fullName 24 | if (lastDot > 0) { 25 | packageName = fullName.substring(0, lastDot) 26 | className = fullName.substring(lastDot + 1, fullName.length) 27 | } 28 | 29 | return Pair(packageName, className) 30 | } 31 | 32 | fun packImports(): MutableMap { 33 | return mapSimpleNames 34 | } 35 | 36 | fun addImport(className: String) { 37 | if (className.startsWith(JAVA_LANG_PACKAGE) || className.startsWith(KOTLIN_LANG_PACKAGE)) { 38 | return 39 | } 40 | 41 | if (DEFAULT_TYPE_NAMES.contains(className)) { 42 | return 43 | } 44 | 45 | val names = splitPackageAndClassName(className) 46 | this.mapSimpleNames[className] = names.second 47 | } 48 | } -------------------------------------------------------------------------------- /legacy/scan_bytecode/src/main/kotlin/org/archguard/scanner/bytecode/module/CodeModule.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.bytecode.module 2 | 3 | class CodeModule(var name: String?, var path: String?, var moduleDependencies: Set?) { 4 | 5 | } -------------------------------------------------------------------------------- /legacy/scan_bytecode/src/main/kotlin/org/archguard/scanner/bytecode/module/NoModuleException.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.bytecode.module 2 | 3 | class NoModuleException : Exception() -------------------------------------------------------------------------------- /legacy/scan_bytecode/src/test/kotlin/org/archguard/scanner/bytecode/ApiParserTest.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.bytecode 2 | 3 | import org.archguard.scanner.analyser.backend.JavaApiAnalyser 4 | import org.junit.jupiter.api.Test 5 | import java.nio.file.Paths 6 | import kotlin.test.assertEquals 7 | 8 | class ApiParserTest { 9 | @Test 10 | fun should_ident_demand_source() { 11 | val resource = this.javaClass.classLoader.getResource("kotlin/QualityGateClientImpl.class") 12 | val path = Paths.get(resource.toURI()).toFile() 13 | val ds = ByteCodeParser().parseClassFile(path) 14 | 15 | val javaApiAnalyser = JavaApiAnalyser() 16 | javaApiAnalyser.analysisByNode(ds, "") 17 | val services = javaApiAnalyser.toContainerServices() 18 | assertEquals(1, services[0].demands.size) 19 | assertEquals("QualityGateClientImpl", services[0].demands[0].source_caller) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /legacy/scan_bytecode/src/test/kotlin/org/archguard/scanner/bytecode/module/ModuleUtilTest.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.bytecode.module 2 | 3 | import org.junit.jupiter.api.Test 4 | import java.nio.file.Paths 5 | import kotlin.test.assertEquals 6 | 7 | internal class ModuleUtilTest { 8 | @Test 9 | internal fun name() { 10 | val path = Paths.get(javaClass.classLoader.getResource("module/gradle").toURI()) 11 | 12 | assertEquals("scan_bytecode", ModuleUtil.getModule(path).name) 13 | assertEquals(0, ModuleUtil.getModule(path).moduleDependencies!!.size) 14 | } 15 | } -------------------------------------------------------------------------------- /legacy/scan_bytecode/src/test/resources/annotation/DemoApplication.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/archguard/scanner/c7723b67ef980af88c078da28c9d2927147daf7a/legacy/scan_bytecode/src/test/resources/annotation/DemoApplication.class -------------------------------------------------------------------------------- /legacy/scan_bytecode/src/test/resources/classes/HelloWorld.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/archguard/scanner/c7723b67ef980af88c078da28c9d2927147daf7a/legacy/scan_bytecode/src/test/resources/classes/HelloWorld.class -------------------------------------------------------------------------------- /legacy/scan_bytecode/src/test/resources/classes/HelloWorld.java: -------------------------------------------------------------------------------- 1 | package org.archguard.demo; 2 | 3 | public class HelloWorld { 4 | public static void main(String[] args) { 5 | System.out.println("Hello, World"); 6 | } 7 | } -------------------------------------------------------------------------------- /legacy/scan_bytecode/src/test/resources/controller/CodeTreeController.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/archguard/scanner/c7723b67ef980af88c078da28c9d2927147daf7a/legacy/scan_bytecode/src/test/resources/controller/CodeTreeController.class -------------------------------------------------------------------------------- /legacy/scan_bytecode/src/test/resources/e2e/build.gradle: -------------------------------------------------------------------------------- 1 | package e2e 2 | 3 | apply plugin: 'java' 4 | apply plugin: 'eclipse' 5 | apply plugin: 'application' 6 | 7 | mainClassName = 'hello.HelloWorld' 8 | 9 | // tag::repositories[] 10 | repositories { 11 | mavenCentral() 12 | } 13 | // end::repositories[] 14 | 15 | // tag::jar[] 16 | jar { 17 | archiveBaseName = 'gs-gradle' 18 | archiveVersion = '0.1.0' 19 | } 20 | // end::jar[] 21 | 22 | // tag::dependencies[] 23 | sourceCompatibility = 1.8 24 | targetCompatibility = 1.8 25 | 26 | dependencies { 27 | implementation "joda-time:joda-time:2.2" 28 | testImplementation "junit:junit:4.12" 29 | } -------------------------------------------------------------------------------- /legacy/scan_bytecode/src/test/resources/e2e/sample/CodeTreeController.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/archguard/scanner/c7723b67ef980af88c078da28c9d2927147daf7a/legacy/scan_bytecode/src/test/resources/e2e/sample/CodeTreeController.class -------------------------------------------------------------------------------- /legacy/scan_bytecode/src/test/resources/e2e/sample/SizingRepositoryImpl.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/archguard/scanner/c7723b67ef980af88c078da28c9d2927147daf7a/legacy/scan_bytecode/src/test/resources/e2e/sample/SizingRepositoryImpl.class -------------------------------------------------------------------------------- /legacy/scan_bytecode/src/test/resources/inheritance/Child.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/archguard/scanner/c7723b67ef980af88c078da28c9d2927147daf7a/legacy/scan_bytecode/src/test/resources/inheritance/Child.class -------------------------------------------------------------------------------- /legacy/scan_bytecode/src/test/resources/inheritance/Hello.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/archguard/scanner/c7723b67ef980af88c078da28c9d2927147daf7a/legacy/scan_bytecode/src/test/resources/inheritance/Hello.class -------------------------------------------------------------------------------- /legacy/scan_bytecode/src/test/resources/inheritance/Interface.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/archguard/scanner/c7723b67ef980af88c078da28c9d2927147daf7a/legacy/scan_bytecode/src/test/resources/inheritance/Interface.class -------------------------------------------------------------------------------- /legacy/scan_bytecode/src/test/resources/kotlin/QualityGateClientImpl.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/archguard/scanner/c7723b67ef980af88c078da28c9d2927147daf7a/legacy/scan_bytecode/src/test/resources/kotlin/QualityGateClientImpl.class -------------------------------------------------------------------------------- /legacy/scan_bytecode/src/test/resources/module/gradle/build.gradle: -------------------------------------------------------------------------------- 1 | package module.gradle 2 | 3 | apply plugin: 'java' 4 | apply plugin: 'eclipse' 5 | apply plugin: 'application' 6 | 7 | mainClassName = 'hello.HelloWorld' 8 | 9 | // tag::repositories[] 10 | repositories { 11 | mavenCentral() 12 | } 13 | // end::repositories[] 14 | 15 | // tag::jar[] 16 | jar { 17 | archiveBaseName = 'gs-gradle' 18 | archiveVersion = '0.1.0' 19 | } 20 | // end::jar[] 21 | 22 | // tag::dependencies[] 23 | sourceCompatibility = 1.8 24 | targetCompatibility = 1.8 25 | 26 | dependencies { 27 | implementation "joda-time:joda-time:2.2" 28 | testImplementation "junit:junit:4.12" 29 | } -------------------------------------------------------------------------------- /legacy/scan_bytecode/src/test/resources/scala/Hello.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/archguard/scanner/c7723b67ef980af88c078da28c9d2927147daf7a/legacy/scan_bytecode/src/test/resources/scala/Hello.class -------------------------------------------------------------------------------- /legacy/scan_bytecode/src/test/resources/scala/Hello.scala: -------------------------------------------------------------------------------- 1 | object Hello { 2 | def main(args: Array[String]) = { 3 | println("Hello, world") 4 | } 5 | } 6 | 7 | -------------------------------------------------------------------------------- /legacy/scan_jacoco/README.md: -------------------------------------------------------------------------------- 1 | ### 说明: 2 | 3 | 扫描目标项目下的 jacoco.exec 文件, 将目标项目的覆盖率数据生成 SQL 文件 output.sql 4 | 5 | ### 构建: 6 | 7 | 8 | ### 运行: 9 | 10 | `java -jar target/scan_jacoco-*.jar --target-project=/path/of/target/project --bin=target/classes --exec=target/jacoco.exec` 11 | 12 | 选项 13 | - target-project, 目标项目的绝对滤镜 14 | - bin, 目标项目的字节码路径,相对路径,缺省 target/classes 15 | - exec, jacoco 文件路径, 缺省 target/jacoco.exec 16 | 17 | 18 | ### 工具 19 | -------------------------------------------------------------------------------- /legacy/scan_jacoco/build.gradle.kts: -------------------------------------------------------------------------------- 1 | group = "com.thoughtworks.archguard.scanners" 2 | description = "scan_jacoco" 3 | 4 | plugins { 5 | id("application") 6 | kotlin("jvm") version "1.6.10" 7 | id("com.github.johnrengelman.shadow") version "7.0.0" 8 | } 9 | 10 | dependencies { 11 | implementation("com.github.ajalt.clikt:clikt:3.4.0") 12 | implementation("org.jetbrains.kotlin:kotlin-reflect:1.3.30") 13 | 14 | implementation("org.jacoco:org.jacoco.core:0.8.7") 15 | } 16 | 17 | application { 18 | mainClass.set("com.thoughtworks.archguard.scanner.jacoco.RunnerKt") 19 | } 20 | -------------------------------------------------------------------------------- /legacy/scan_jacoco/src/main/kotlin/com/thoughtworks/archguard/scanner/jacoco/Bean2Sql.kt: -------------------------------------------------------------------------------- 1 | package com.thoughtworks.archguard.scanner.jacoco 2 | 3 | import kotlin.reflect.full.findAnnotation 4 | import kotlin.reflect.full.memberProperties 5 | 6 | 7 | class Bean2Sql { 8 | fun bean2Sql(bean: Any): String { 9 | val clazz = bean::class 10 | val table = clazz.findAnnotation()?.value ?: clazz.simpleName 11 | val columns = arrayListOf() 12 | val values = arrayListOf() 13 | clazz.memberProperties.forEach { property -> 14 | val column = property.findAnnotation()?.value ?: property.name 15 | columns.add(column) 16 | values.add(property.call(bean)) 17 | } 18 | val valueString = values.joinToString { 19 | if (it is String) { 20 | "'${it.replace("'", "''")}'"// do with like it's -- there is a ' within string 21 | } else if (it is Enum<*>) { 22 | "'$it'" 23 | } else it.toString() 24 | } 25 | 26 | return "insert into test_coverage_$table(${columns.joinToString()}) values($valueString);" 27 | } 28 | } -------------------------------------------------------------------------------- /legacy/scan_jacoco/src/main/kotlin/com/thoughtworks/archguard/scanner/jacoco/Runner.kt: -------------------------------------------------------------------------------- 1 | package com.thoughtworks.archguard.scanner.jacoco 2 | 3 | import com.github.ajalt.clikt.core.CliktCommand 4 | import com.github.ajalt.clikt.parameters.options.default 5 | import com.github.ajalt.clikt.parameters.options.option 6 | 7 | class Runner : CliktCommand() { 8 | private val targetProject: String by option(help = "the path of target proejct").default(".") 9 | private val bin: String by option(help = "relative path of binary").default("build/classes") 10 | private val exec: String by option(help = "jacoco data file").default("build/jacoco/test.exec") 11 | 12 | override fun run() { 13 | JacocoService(Bean2Sql()).readJacoco(Config(projectPath = targetProject, bin = bin, exec = exec)) 14 | } 15 | } 16 | 17 | fun main(args: Array) = Runner().main(args) 18 | 19 | 20 | -------------------------------------------------------------------------------- /legacy/scan_jacoco/src/main/resources/db/migration/db_recreate_and_load.sh: -------------------------------------------------------------------------------- 1 | mysql --verbose --database=archguard --user=root -e "source ddl.sql" 2 | mysql --database=archguard --user=root -e "source ../../../../../output.sql" -------------------------------------------------------------------------------- /legacy/scan_jacoco/src/main/resources/db/migration/ddl.sql: -------------------------------------------------------------------------------- 1 | -- for mysql 2 | 3 | drop table if exists bundle; 4 | create table bundle( 5 | instruction_missed int, 6 | instruction_covered int, 7 | line_missed int, 8 | line_covered int, 9 | branch_missed int, 10 | branch_covered int, 11 | complexity_missed int, 12 | complexity_covered int, 13 | method_missed int, 14 | method_covered int, 15 | class_missed int, 16 | class_covered int, 17 | bundle_name varchar(50), 18 | scan_time bigint, 19 | primary key(bundle_name,scan_time) 20 | ); 21 | 22 | 23 | drop table if exists item; 24 | create table item( 25 | instruction_missed int, 26 | instruction_covered int, 27 | line_missed int, 28 | line_covered int, 29 | branch_missed int, 30 | branch_covered int, 31 | complexity_missed int, 32 | complexity_covered int, 33 | method_missed int, 34 | method_covered int, 35 | class_missed int, 36 | class_covered int, 37 | item_type varchar(10), 38 | item_name varchar(50), 39 | bundle_name varchar(50), 40 | scan_time bigint, 41 | primary key(item_name,bundle_name,scan_time) 42 | ); 43 | 44 | -------------------------------------------------------------------------------- /legacy/scan_jacoco/src/main/resources/db/migration/import_data_2_cloudDB.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | PRO_DIR=../../../../../ 4 | REMOTE=jenkin@archguard-pipeline.southeastasia.cloudapp.azure.com 5 | WDR=/home/jenkin/sampleData4Git/ 6 | DDL=$WDR/ddl.sql 7 | DML=$WDR/output.sql 8 | 9 | ssh $REMOTE "mkdir $WDR" 10 | 11 | scp $PRO_DIR/src/main/resources/db/migration/ddl.sql $REMOTE:$DDL 12 | scp $PRO_DIR/output.sql $REMOTE:$DML 13 | 14 | ssh $REMOTE < 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /legacy/scan_jacoco/src/test/kotlin/com/thoughtworks/archguard/scanner/jacoco/JacocoServiceTest.kt: -------------------------------------------------------------------------------- 1 | package com.thoughtworks.archguard.scanner.jacoco 2 | 3 | import org.junit.jupiter.api.Test 4 | import java.io.File 5 | 6 | internal class JacocoServiceTest { 7 | 8 | @Test 9 | fun readJacoco() { 10 | val resource = this.javaClass.classLoader.getResource("parent").path 11 | JacocoService(Bean2Sql()).readJacoco(Config(projectPath = resource, bin = "classes", exec = "jacoco/jacoco.exec")) 12 | 13 | assert(File("jacoco.sql").exists()) 14 | 15 | val text = File("jacoco.sql").readText() 16 | assert(text.contains("Model.kt")) 17 | } 18 | } -------------------------------------------------------------------------------- /legacy/scan_jacoco/src/test/resources/parent/classes/CommitLog.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/archguard/scanner/c7723b67ef980af88c078da28c9d2927147daf7a/legacy/scan_jacoco/src/test/resources/parent/classes/CommitLog.class -------------------------------------------------------------------------------- /legacy/scan_jacoco/src/test/resources/parent/jacoco/jacoco.exec: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/archguard/scanner/c7723b67ef980af88c078da28c9d2927147daf7a/legacy/scan_jacoco/src/test/resources/parent/jacoco/jacoco.exec -------------------------------------------------------------------------------- /legacy/scan_test_badsmell/build.gradle.kts: -------------------------------------------------------------------------------- 1 | group = "com.thoughtworks.archguard.scanner" 2 | 3 | plugins { 4 | id("application") 5 | kotlin("jvm") version "1.6.10" 6 | id("com.github.johnrengelman.shadow") version "7.0.0" 7 | 8 | kotlin("plugin.serialization") version "1.6.10" 9 | } 10 | 11 | dependencies { 12 | api(project(":rule-core")) 13 | api(project(":linter:rule-test-code")) 14 | 15 | implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.2") 16 | 17 | implementation("com.github.ajalt.clikt:clikt:3.4.0") 18 | 19 | implementation("com.phodal.chapi:chapi-domain:1.5.6") 20 | implementation("com.phodal.chapi:chapi-application:1.5.6") 21 | } 22 | 23 | application { 24 | mainClass.set("org.archguard.scanner.tbs.RunnerKt") 25 | } 26 | 27 | tasks{ 28 | shadowJar { 29 | manifest { 30 | attributes(Pair("Main-Class", "org.archguard.scanner.tbs.RunnerKt")) 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /legacy/scan_test_badsmell/src/main/kotlin/org/archguard/scanner/tbs/Runner.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.tbs 2 | 3 | import com.github.ajalt.clikt.core.CliktCommand 4 | import com.github.ajalt.clikt.parameters.options.default 5 | import com.github.ajalt.clikt.parameters.options.option 6 | import kotlinx.serialization.encodeToString 7 | import kotlinx.serialization.json.Json 8 | import java.io.File 9 | 10 | public val OUTPUT_FILE = "bs.json" 11 | 12 | class Runner : CliktCommand(help = "collect test bad smell") { 13 | private val path: String by option(help = "local path").default(".") 14 | 15 | override fun run() { 16 | val results = TbsAnalyser().analysisByPath(path) 17 | File(OUTPUT_FILE).writeText(Json.encodeToString(results)) 18 | } 19 | } 20 | 21 | fun main(args: Array) = Runner().main(args) 22 | 23 | -------------------------------------------------------------------------------- /legacy/scan_test_badsmell/src/main/kotlin/org/archguard/scanner/tbs/TbsAnalyser.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.tbs 2 | 3 | import chapi.app.analyser.ChapiAnalyser 4 | import chapi.app.analyser.config.ChapiConfig 5 | import kotlinx.serialization.Serializable 6 | import org.archguard.linter.rule.testcode.TestSmellProvider 7 | import org.archguard.linter.rule.testcode.TestSmellVisitor 8 | 9 | @Serializable 10 | open class TestBadSmell( 11 | var fileName: String = "", 12 | var type: String = "", 13 | var description: String = "", 14 | var line: Int = 0 15 | ) 16 | 17 | class TbsAnalyser( 18 | private val config: ChapiConfig = ChapiConfig() 19 | ) { 20 | fun analysisByPath(path: String): Array { 21 | val nodes = ChapiAnalyser(config).analysis(path) 22 | 23 | val provider = TestSmellProvider() 24 | val visitor = TestSmellVisitor(nodes) 25 | return nodes.flatMap { ds -> 26 | visitor 27 | .visitor(listOf(provider.get()), ds) 28 | .map { 29 | TestBadSmell( 30 | fileName = ds.FilePath, 31 | type = it.name, 32 | description = it.detail, 33 | line = it.position.startLine 34 | ) 35 | } 36 | }.toTypedArray() 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /legacy/scan_test_badsmell/src/test/kotlin/org/archguard/scanner/tbs/RunnerKtTest.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.tbs 2 | 3 | import org.junit.jupiter.api.Assertions.* 4 | import org.junit.jupiter.api.Test 5 | import java.io.File 6 | 7 | internal class RunnerKtTest { 8 | @Test 9 | internal fun name() { 10 | Runner().main(arrayOf("--path=.")) 11 | assertTrue(File(OUTPUT_FILE).exists()) 12 | } 13 | } -------------------------------------------------------------------------------- /legacy/scan_test_badsmell/src/test/kotlin/org/archguard/scanner/tbs/RunnerTest.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.tbs 2 | 3 | import org.junit.jupiter.api.Test 4 | import java.io.File 5 | import kotlin.test.assertTrue 6 | 7 | internal class RunnerTest { 8 | 9 | @Test 10 | fun run() { 11 | val file = File(OUTPUT_FILE) 12 | Runner().main(arrayOf("--path=.")) 13 | assertTrue(file.exists()) 14 | 15 | val content = File(OUTPUT_FILE).readText() 16 | assertTrue(content.contains("RedundantPrintTest")) 17 | assertTrue(content.contains("UnknownTest")) 18 | assertTrue(content.contains("DuplicateAssertTest")) 19 | assertTrue(content.contains("EmptyTest")) 20 | assertTrue(content.contains("SleepyTest")) 21 | } 22 | } -------------------------------------------------------------------------------- /legacy/scan_test_badsmell/src/test/resources/regression/CreatorNotUnknownTest.java: -------------------------------------------------------------------------------- 1 | package cc.arduino.packages.contributions; 2 | 3 | import org.junit.Test; 4 | import processing.app.Platform; 5 | 6 | import static org.junit.Assert.assertFalse; 7 | import static org.junit.Assert.assertTrue; 8 | 9 | public class HostDependentDownloadableContributionTest { 10 | @Test 11 | public void macOsXPositiveTest() { 12 | HostDependentDownloadableContributionStub contribution = new HostDependentDownloadableContributionStub() { 13 | @Override 14 | public String getHost() { 15 | return "x86_64-apple-darwin"; 16 | } 17 | }; 18 | 19 | Platform platform = new Platform() { 20 | @Override 21 | public String getOsName() { 22 | return "Mac OS X"; 23 | } 24 | 25 | @Override 26 | public String getOsArch() { 27 | return "x86_64"; 28 | } 29 | }; 30 | 31 | assertTrue(contribution.isCompatible(platform)); 32 | } 33 | } -------------------------------------------------------------------------------- /legacy/scan_test_badsmell/src/test/resources/tbs/go/empty_test.go: -------------------------------------------------------------------------------- 1 | package tbs 2 | 3 | import "testing" 4 | 5 | func TestTbsApp_EmptyTest(t *testing.T) { 6 | 7 | } 8 | -------------------------------------------------------------------------------- /legacy/scan_test_badsmell/src/test/resources/tbs/usecases/AssertionRouletteTest.java: -------------------------------------------------------------------------------- 1 | package tbs; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.assertEquals; 6 | import static org.junit.Assert.assertThat; 7 | 8 | public class AssertionRouletteTest { 9 | @Test 10 | public void testCloneNonBareRepoFromLocalTestServer() throws Exception { 11 | Calculate calculate = new Calculate(); 12 | int result = calculate.add(7, 8); 13 | int success = 15; 14 | assertEquals(success, result); 15 | 16 | int subResult = calculate.sub(9, 2); 17 | int subSuccess = 7; 18 | assertEquals(subSuccess, subResult); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /legacy/scan_test_badsmell/src/test/resources/tbs/usecases/ConditionalTest.java: -------------------------------------------------------------------------------- 1 | package tbs; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.assertEquals; 6 | 7 | public class ConditionalTest { 8 | @Test 9 | public void byGod() { 10 | Calculate calculate = new Calculate(); 11 | // just examples 12 | if (calculate.add(7, 9) == 16) { 13 | if (calculate.sub(12, 9) == 3) { 14 | int subSuccess = 7; 15 | assertEquals(subSuccess, calculate.sub(9, 2)); 16 | } 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /legacy/scan_test_badsmell/src/test/resources/tbs/usecases/ConstructorInitializationTest.java: -------------------------------------------------------------------------------- 1 | package tbs; 2 | 3 | import org.junit.Before; 4 | import org.junit.Test; 5 | 6 | import static org.junit.Assert.assertEquals; 7 | 8 | public class ConstructorInitializationTest { 9 | @Before 10 | public void init() throws Exception { 11 | 12 | } 13 | 14 | @Test 15 | public void name() { 16 | Calculate calculate = new Calculate(); 17 | int result = calculate.add(7, 8); 18 | int success = 15; 19 | assertEquals(success, result); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /legacy/scan_test_badsmell/src/test/resources/tbs/usecases/DuplicateAssertTest.java: -------------------------------------------------------------------------------- 1 | package tbs; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.assertEquals; 6 | 7 | public class DuplicateAssertTest { 8 | @Test 9 | public void testXmlSanitizer() { 10 | boolean valid = XmlSanitizer.isValid("Fritzbox"); 11 | assertEquals("Fritzbox is valid", true, valid); 12 | 13 | valid = XmlSanitizer.isValid("Fritz Box"); 14 | assertEquals("Spaces are valid", true, valid); 15 | 16 | valid = XmlSanitizer.isValid("Frützbüx"); 17 | assertEquals("Frützbüx is invalid", false, valid); 18 | 19 | valid = XmlSanitizer.isValid("Fritz!box"); 20 | assertEquals("Exclamation mark is valid", true, valid); 21 | 22 | valid = XmlSanitizer.isValid("Fritz!box"); 23 | assertEquals("Exclamation mark is valid", true, valid); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /legacy/scan_test_badsmell/src/test/resources/tbs/usecases/EmptyTest.java: -------------------------------------------------------------------------------- 1 | package tbs; 2 | 3 | import org.junit.Test; 4 | 5 | public class EmptyTest { 6 | 7 | @Test 8 | public void testCredGetFullSampleV1() throws Throwable { 9 | // ScrapedCredentials credentials = innerCredTest(FULL_SAMPLE_v1); 10 | // assertEquals("p4ssw0rd", credentials.pass); 11 | // assertEquals("user@example.com",credentials.user); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /legacy/scan_test_badsmell/src/test/resources/tbs/usecases/IgnoreTest.java: -------------------------------------------------------------------------------- 1 | package tbs; 2 | 3 | import org.junit.Ignore; 4 | 5 | public class IgnoreTest { 6 | @Ignore("Oops, Not Time fix it") 7 | public void peerPriority() throws Exception { 8 | 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /legacy/scan_test_badsmell/src/test/resources/tbs/usecases/MagicNumberTest.java: -------------------------------------------------------------------------------- 1 | package tbs; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.Calendar; 6 | 7 | import static org.junit.Assert.assertEquals; 8 | 9 | public class MagicNumberTest { 10 | @Test 11 | public void testGetLocalTimeAsCalendar() { 12 | int result = 7 + 8; 13 | assertEquals(15, result); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /legacy/scan_test_badsmell/src/test/resources/tbs/usecases/MysteryGuestTest.java: -------------------------------------------------------------------------------- 1 | package tbs; 2 | 3 | import org.junit.Test; 4 | 5 | import java.io.FileNotFoundException; 6 | import java.io.FileOutputStream; 7 | import java.io.IOException; 8 | 9 | public class MysteryGuestTest { 10 | @Test 11 | public void testPersistence() throws Exception { 12 | try (FileOutputStream out = new FileOutputStream("people.bin");) { 13 | int result = 5; 14 | out.write(result); 15 | } catch (FileNotFoundException e) { 16 | // blabla 17 | } catch (IOException e) { 18 | // blabla 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /legacy/scan_test_badsmell/src/test/resources/tbs/usecases/RedundantAssertionTest.java: -------------------------------------------------------------------------------- 1 | package tbs; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.assertEquals; 6 | 7 | public class RedundantAssertionTest { 8 | @Test 9 | public void testTrue() { 10 | Calculate calculate = new Calculate(); 11 | int result = calculate.add(7, 8); 12 | int success = 15; 13 | 14 | assertEquals(true, true); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /legacy/scan_test_badsmell/src/test/resources/tbs/usecases/RedundantPrintTest.java: -------------------------------------------------------------------------------- 1 | package tbs; 2 | 3 | import org.junit.Test; 4 | 5 | public class RedundantPrintTest { 6 | @Test 7 | public void testTransform10mNEUAndBack() { 8 | String result = "a, b, c"; 9 | System.out.println("result = " + result); 10 | assertEquals(true, true); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /legacy/scan_test_badsmell/src/test/resources/tbs/usecases/SleepyTest.java: -------------------------------------------------------------------------------- 1 | package tbs; 2 | 3 | import org.junit.Test; 4 | 5 | public class SleepyTest { 6 | @Test 7 | public void testEdictExternSearch() throws Exception { 8 | Thread.sleep(500); 9 | assertEquals(true, true); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /legacy/scan_test_badsmell/src/test/resources/tbs/usecases/TestersOnly.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * public for test call only 4 | * 5 | */ 6 | -------------------------------------------------------------------------------- /legacy/scan_test_badsmell/src/test/resources/tbs/usecases/UnknownTest.java: -------------------------------------------------------------------------------- 1 | package tbs; 2 | 3 | import org.junit.Test; 4 | 5 | public class UnknownTest { 6 | @Test 7 | public void hitGetPOICategoriesApi() throws Exception { 8 | String a = "blabla"; 9 | String b = "blablac"; 10 | String c = a + b; 11 | Show(a, b); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /rule-core/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | kotlin("jvm") version "1.6.10" 3 | kotlin("plugin.serialization") version "1.6.10" 4 | } 5 | 6 | dependencies { 7 | testImplementation("org.jetbrains.kotlin:kotlin-reflect:1.6.10") 8 | testImplementation("org.reflections:reflections:0.10.2") 9 | 10 | implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.2") 11 | } 12 | -------------------------------------------------------------------------------- /rule-core/src/main/kotlin/org/archguard/rule/common/Language.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.rule.common 2 | 3 | enum class Language { 4 | JAVA, 5 | KOTLIN, 6 | CSHARP, 7 | PYTHON, 8 | GO, 9 | TYPESCRIPT, 10 | JAVASCRIPT 11 | } 12 | -------------------------------------------------------------------------------- /rule-core/src/main/kotlin/org/archguard/rule/core/IfttRule.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.rule.core 2 | 3 | abstract class IfttRule : Rule() { 4 | fun given(conditions: List): IfttRule { 5 | return this 6 | } 7 | 8 | fun then(conditions: List): IfttRule { 9 | return this 10 | } 11 | } -------------------------------------------------------------------------------- /rule-core/src/main/kotlin/org/archguard/rule/core/Issue.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.rule.core 2 | 3 | import kotlinx.serialization.Serializable 4 | 5 | /** 6 | * **Issue** is the analysis result of items. 7 | */ 8 | @Serializable 9 | class Issue( 10 | val position: IssuePosition, 11 | val ruleId: String, 12 | val name: String, 13 | val detail: String, 14 | val ruleType: RuleType 15 | ) 16 | -------------------------------------------------------------------------------- /rule-core/src/main/kotlin/org/archguard/rule/core/IssuePosition.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.rule.core 2 | 3 | import kotlinx.serialization.Serializable 4 | 5 | @Serializable 6 | class IssuePosition ( 7 | var startLine: Int = 0, 8 | var startColumn: Int = 0, 9 | var endLine: Int = 0, 10 | var endColumn: Int = 0 11 | ) { 12 | override fun toString(): String { 13 | return "IssuePosition(startLine=$startLine, startColumn=$startColumn, endLine=$endLine, endColumn=$endColumn)" 14 | } 15 | } -------------------------------------------------------------------------------- /rule-core/src/main/kotlin/org/archguard/rule/core/RuleSet.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.rule.core 2 | 3 | /** 4 | * **RuleSet** contains a set of Rules 5 | */ 6 | open class RuleSet( 7 | var type: RuleType, 8 | val name: String, 9 | vararg val rules: Rule 10 | ) : Iterable { 11 | override fun iterator(): Iterator = rules.iterator() 12 | } 13 | -------------------------------------------------------------------------------- /rule-core/src/main/kotlin/org/archguard/rule/core/RuleSetProvider.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.rule.core 2 | 3 | import java.io.Serializable 4 | 5 | interface RuleSetProvider: Serializable { 6 | fun get(): RuleSet 7 | } -------------------------------------------------------------------------------- /rule-core/src/main/kotlin/org/archguard/rule/core/RuleVisitor.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.rule.core 2 | 3 | 4 | abstract class RuleVisitor(val data: Iterable) { 5 | abstract fun visitor(ruleSets: Iterable): List 6 | // for disabled rules, we can set in backend. 7 | // abstract fun concurrentVisitor(enabledRules: Map, ruleSets: Iterable): List 8 | } 9 | -------------------------------------------------------------------------------- /rule-doc-generator/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("application") 3 | kotlin("jvm") version "1.6.10" 4 | id("com.github.johnrengelman.shadow") version "7.0.0" 5 | kotlin("plugin.serialization") version "1.6.10" 6 | } 7 | 8 | dependencies { 9 | api(project(":rule-core")) 10 | api(project(":rule-linter:rule-code")) 11 | api(project(":rule-linter:rule-sql")) 12 | api(project(":rule-linter:rule-test-code")) 13 | api(project(":rule-linter:rule-webapi")) 14 | 15 | api("org.jetbrains.kotlin:kotlin-compiler:1.6.10") 16 | 17 | implementation("io.github.microutils:kotlin-logging:2.1.21") 18 | implementation("com.github.ajalt.clikt:clikt:3.4.0") 19 | implementation("org.jetbrains.kotlin:kotlin-reflect:1.3.30") 20 | } 21 | 22 | application { 23 | mainClass.set("org.archguard.doc.generator.RunnerKt") 24 | } 25 | 26 | tasks { 27 | shadowJar { 28 | manifest { 29 | attributes(Pair("Main-Class", "org.archguard.doc.generator.RunnerKt")) 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /rule-doc-generator/src/main/kotlin/org/archguard/doc/generator/Runner.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.doc.generator 2 | 3 | import com.github.ajalt.clikt.core.CliktCommand 4 | import com.github.ajalt.clikt.parameters.options.default 5 | import com.github.ajalt.clikt.parameters.options.option 6 | 7 | class Runner : CliktCommand() { 8 | override fun run() { 9 | RuleDocGenerator().execute() 10 | } 11 | } 12 | 13 | fun main(args: Array) = Runner().main(args) 14 | 15 | -------------------------------------------------------------------------------- /rule-doc-generator/src/main/kotlin/org/archguard/doc/generator/compiler/DocMessageCollector.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.doc.generator.compiler 2 | 3 | import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity 4 | import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSourceLocation 5 | import org.jetbrains.kotlin.cli.common.messages.MessageCollector 6 | import org.jetbrains.kotlin.cli.common.messages.MessageRenderer 7 | 8 | class DocMessageCollector(var logger: org.slf4j.Logger): MessageCollector { 9 | override fun clear() { 10 | seenErrors = false 11 | } 12 | 13 | private var seenErrors = false 14 | 15 | override fun report(severity: CompilerMessageSeverity, message: String, location: CompilerMessageSourceLocation?) { 16 | if (severity == CompilerMessageSeverity.ERROR) { 17 | seenErrors = true 18 | } 19 | logger.info(MessageRenderer.PLAIN_FULL_PATHS.render(severity, message, location)) 20 | } 21 | 22 | override fun hasErrors() = seenErrors 23 | } -------------------------------------------------------------------------------- /rule-doc-generator/src/main/kotlin/org/archguard/doc/generator/render/MarkdownRenderImpl.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.doc.generator.render 2 | 3 | class MarkdownRenderImpl : Render() { 4 | override fun T.buildMetadata(content: T.() -> Unit) { 5 | 6 | } 7 | 8 | override fun T.buildLink(address: String, content: T.() -> Unit) { 9 | 10 | } 11 | 12 | override fun T.buildLineBreak() { 13 | 14 | 15 | } 16 | } -------------------------------------------------------------------------------- /rule-doc-generator/src/main/kotlin/org/archguard/doc/generator/render/Render.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.doc.generator.render 2 | 3 | abstract class Render { 4 | abstract fun T.buildMetadata(content: T.() -> Unit) 5 | abstract fun T.buildLink(address: String, content: T.() -> Unit) 6 | abstract fun T.buildLineBreak() 7 | } 8 | 9 | interface ContentNode 10 | 11 | data class DocPage(var content: List) : ContentNode 12 | data class DocHeader(val title: String, val content: List, val level: Int) : ContentNode 13 | data class DocText(val text: String) : ContentNode 14 | data class DocBreakLine(val text: String = "") : ContentNode 15 | data class DocCodeBlock(val language: String, val text: String) : ContentNode 16 | 17 | data class CustomJekyllFrontMatter( 18 | val layout: String = "default", 19 | var title: String, 20 | val parent: String = "Governance", 21 | val navOrder: Int, 22 | val permalink: String, 23 | ) : ContentNode { 24 | 25 | fun toMarkdown(): String { 26 | return """ 27 | --- 28 | layout: $layout 29 | title: $title 30 | parent: $parent 31 | nav_order: $navOrder 32 | permalink: /governance/$permalink 33 | --- 34 | 35 | """.trimIndent() 36 | } 37 | } -------------------------------------------------------------------------------- /rule-doc-generator/src/test/kotlin/org/archguard/doc/generator/render/CustomJekyllFrontMatterTest.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.doc.generator.render 2 | 3 | import org.junit.jupiter.api.Test 4 | import kotlin.test.assertEquals 5 | 6 | internal class CustomJekyllFrontMatterTest { 7 | @Test 8 | internal fun head_to_text() { 9 | val fm = CustomJekyllFrontMatter(title = "SQL", navOrder = 1, permalink = "sql") 10 | assertEquals("""--- 11 | layout: default 12 | title: SQL 13 | parent: Governance 14 | nav_order: 1 15 | permalink: /governance/sql 16 | --- 17 | """, fm.toMarkdown()) 18 | } 19 | } -------------------------------------------------------------------------------- /rule-linter/README.md: -------------------------------------------------------------------------------- 1 | # Linter 2 | 3 | - [ ] SQL 4 | - [ ] Test Code 5 | - [ ] Web API 6 | - [ ] Layered arch 7 | -------------------------------------------------------------------------------- /rule-linter/rule-code/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | kotlin("jvm") version "1.6.10" 3 | kotlin("plugin.serialization") version "1.6.10" 4 | } 5 | 6 | dependencies { 7 | api(project(":rule-core")) 8 | 9 | api("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.2") 10 | 11 | implementation("com.phodal.chapi:chapi-domain:1.5.6") 12 | implementation("org.jetbrains.kotlin:kotlin-reflect:1.6.10") 13 | } 14 | -------------------------------------------------------------------------------- /rule-linter/rule-code/src/main/kotlin/org/archguard/linter/rule/code/AstRuleSetProvider.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.linter.rule.code 2 | 3 | import org.archguard.rule.core.RuleSet 4 | import org.archguard.rule.core.RuleSetProvider 5 | import org.archguard.rule.core.RuleType 6 | 7 | /* 8 | * Low level provider 9 | */ 10 | class AstRuleSetProvider: RuleSetProvider { 11 | override fun get(): RuleSet { 12 | return RuleSet( 13 | RuleType.CHANGE_SMELL, 14 | "normal", 15 | ) 16 | } 17 | } -------------------------------------------------------------------------------- /rule-linter/rule-code/src/main/kotlin/org/archguard/linter/rule/code/AstRuleVisitor.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.linter.rule.code 2 | 3 | import chapi.domain.core.CodeDataStruct 4 | import org.archguard.rule.core.Issue 5 | import org.archguard.rule.core.RuleSet 6 | import org.archguard.rule.core.RuleVisitor 7 | 8 | /* 9 | * Low level provider 10 | */ 11 | class AstRuleVisitor(rootNode: List) : RuleVisitor(rootNode) { 12 | override fun visitor(ruleSets: Iterable): List { 13 | return listOf() 14 | } 15 | } -------------------------------------------------------------------------------- /rule-linter/rule-code/src/main/kotlin/org/archguard/linter/rule/code/AstRulesetContext.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.linter.rule.code 2 | 3 | class AstPath( 4 | // like 5 | val pathItem: String, 6 | // http operation sample: ^(get|put|post|delete|options|head|patch|trace)$ 7 | val operationObject: String, 8 | ) { 9 | fun resolveAlias() { 10 | 11 | } 12 | } 13 | 14 | class AstRulesetContext( 15 | path: AstPath 16 | ) { 17 | 18 | } -------------------------------------------------------------------------------- /rule-linter/rule-code/src/main/resources/META-INF/services/org.archguard.rule.core.RuleSetProvider: -------------------------------------------------------------------------------- 1 | org.archguard.linter.rule.code.AstRuleSetProvider -------------------------------------------------------------------------------- /rule-linter/rule-code/src/main/resources/META-INF/services/org.archguard.rule.core.RuleVisitor: -------------------------------------------------------------------------------- 1 | org.archguard.linter.rule.code.AstRuleVisitor -------------------------------------------------------------------------------- /rule-linter/rule-sql/README.md: -------------------------------------------------------------------------------- 1 | # Ident Mysql 2 | 3 | use JSQLParser: [https://github.com/JSQLParser/JSqlParser/wiki/Examples-of-SQL-parsing](https://github.com/JSQLParser/JSqlParser/wiki/Examples-of-SQL-parsing) 4 | 5 | -------------------------------------------------------------------------------- /rule-linter/rule-sql/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | kotlin("jvm") version "1.6.10" 3 | } 4 | 5 | dependencies { 6 | api(project(":rule-core")) 7 | 8 | implementation("com.github.jsqlparser:jsqlparser:4.4") 9 | implementation("org.jetbrains.kotlin:kotlin-reflect:1.6.10") 10 | } 11 | -------------------------------------------------------------------------------- /rule-linter/rule-sql/src/main/kotlin/org/archguard/linter/rule/sql/SqlRuleSetProvider.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.linter.rule.sql 2 | 3 | import org.archguard.linter.rule.sql.rules.LikeStartWithoutPercentRule 4 | import org.archguard.linter.rule.sql.rules.UnknownColumnSizeRule 5 | import org.archguard.linter.rule.sql.rules.create.AtLeastOnePrimaryKeyRule 6 | import org.archguard.linter.rule.sql.rules.create.LimitColumnSizeRule 7 | import org.archguard.linter.rule.sql.rules.create.SnakeCaseNamingRule 8 | import org.archguard.linter.rule.sql.rules.create.LimitTableNameLengthRule 9 | import org.archguard.linter.rule.sql.rules.expression.LimitJoinsRule 10 | import org.archguard.linter.rule.sql.rules.insert.InsertWithoutField 11 | import org.archguard.rule.core.RuleSet 12 | import org.archguard.rule.core.RuleSetProvider 13 | import org.archguard.rule.core.RuleType 14 | 15 | class SqlRuleSetProvider: RuleSetProvider { 16 | override fun get(): RuleSet { 17 | return RuleSet( 18 | RuleType.SQL_SMELL, 19 | "normal", 20 | UnknownColumnSizeRule(), 21 | LikeStartWithoutPercentRule(), 22 | LimitTableNameLengthRule(), 23 | SnakeCaseNamingRule(), 24 | InsertWithoutField(), 25 | LimitJoinsRule(), 26 | AtLeastOnePrimaryKeyRule(), 27 | LimitColumnSizeRule() 28 | ) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /rule-linter/rule-sql/src/main/kotlin/org/archguard/linter/rule/sql/SqlRuleVisitor.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.linter.rule.sql 2 | 3 | import net.sf.jsqlparser.statement.Statement 4 | import org.archguard.rule.core.Issue 5 | import org.archguard.rule.core.IssuePosition 6 | import org.archguard.rule.core.Rule 7 | import org.archguard.rule.core.RuleContext 8 | import org.archguard.rule.core.RuleSet 9 | import org.archguard.rule.core.RuleType 10 | import org.archguard.rule.core.RuleVisitor 11 | 12 | class SqlRuleVisitor(private val statements: List) : RuleVisitor(statements) { 13 | override fun visitor(ruleSets: Iterable): List { 14 | val results: MutableList = mutableListOf() 15 | val context = RuleContext() 16 | 17 | ruleSets.forEach { ruleSet -> 18 | ruleSet.rules.forEach { rule -> 19 | // todo: cast by plugins 20 | val sqlRule = rule as SqlRule 21 | sqlRule.visit(statements, context, fun(rule: Rule, position: IssuePosition) { 22 | results += Issue( 23 | position, 24 | ruleId = rule.key, 25 | name = rule.name, 26 | detail = rule.description, 27 | ruleType = RuleType.HTTP_API_SMELL 28 | ) 29 | }) 30 | } 31 | } 32 | 33 | return results 34 | } 35 | 36 | } -------------------------------------------------------------------------------- /rule-linter/rule-sql/src/main/kotlin/org/archguard/linter/rule/sql/rules/UnknownColumnSizeRule.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.linter.rule.sql.rules 2 | 3 | import net.sf.jsqlparser.statement.select.PlainSelect 4 | import net.sf.jsqlparser.statement.select.Select 5 | import org.archguard.linter.rule.sql.SqlRule 6 | import org.archguard.rule.core.IssueEmit 7 | import org.archguard.rule.core.IssuePosition 8 | import org.archguard.rule.core.RuleContext 9 | import org.archguard.rule.core.Severity 10 | 11 | class UnknownColumnSizeRule : SqlRule() { 12 | init { 13 | this.id = "unknown-column-size" 14 | this.name = "UnknownColumnSize" 15 | this.key = this.javaClass.name 16 | this.description = "禁止使用 SELECT * 进行查询。建议按需求选择合适的字段列,杜绝直接 SELECT * 读取全部字段,减少网络带宽消耗,有效利用覆盖索引;" 17 | this.severity = Severity.BLOCKER 18 | } 19 | 20 | override fun visitSelect(select: Select, context: RuleContext, callback: IssueEmit) { 21 | when (val selectBody = select.selectBody) { 22 | is PlainSelect -> { 23 | if (selectBody.selectItems.size == 1 && selectBody.selectItems[0].toString() == "*") { 24 | callback(this, IssuePosition()) 25 | } 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /rule-linter/rule-sql/src/main/kotlin/org/archguard/linter/rule/sql/rules/create/AtLeastOnePrimaryKeyRule.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.linter.rule.sql.rules.create 2 | 3 | import net.sf.jsqlparser.statement.create.table.CreateTable 4 | import org.archguard.linter.rule.sql.SqlRule 5 | import org.archguard.rule.core.IssueEmit 6 | import org.archguard.rule.core.IssuePosition 7 | import org.archguard.rule.core.RuleContext 8 | import org.archguard.rule.core.Severity 9 | 10 | class AtLeastOnePrimaryKeyRule : SqlRule() { 11 | init { 12 | this.id = "at-least-one-primary-key" 13 | this.name = "AtLeastOnePrimaryKey" 14 | this.key = this.javaClass.name 15 | this.description = "至少包含一个 Primary Key。" 16 | this.severity = Severity.WARN 17 | } 18 | 19 | override fun visitCreateTable(createStmt: CreateTable, context: RuleContext, callback: IssueEmit) { 20 | if (createStmt.columnDefinitions != null) { 21 | var hasPrimaryKey = false 22 | createStmt.columnDefinitions.forEach { 23 | if (it.columnSpecs != null) { 24 | val specs = it.columnSpecs.joinToString(" ").lowercase() 25 | if (specs.contains("primary")) { 26 | hasPrimaryKey = true 27 | } 28 | } 29 | } 30 | 31 | if (!hasPrimaryKey) { 32 | callback(this, IssuePosition()) 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /rule-linter/rule-sql/src/main/kotlin/org/archguard/linter/rule/sql/rules/create/LimitColumnSizeRule.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.linter.rule.sql.rules.create 2 | 3 | import net.sf.jsqlparser.statement.create.table.CreateTable 4 | import org.archguard.linter.rule.sql.SqlRule 5 | import org.archguard.rule.core.IssueEmit 6 | import org.archguard.rule.core.IssuePosition 7 | import org.archguard.rule.core.RuleContext 8 | import org.archguard.rule.core.Severity 9 | 10 | class LimitColumnSizeRule : SqlRule() { 11 | private val MAX_COLUMN_SIZE = 20 12 | private var maxColumnSize: Int = 0 13 | 14 | init { 15 | this.id = "limit-column-size" 16 | this.name = "LimitColumnSize" 17 | this.key = this.javaClass.name 18 | this.maxColumnSize = this.MAX_COLUMN_SIZE 19 | this.description = "表的字段应该控制在 20 以内。" 20 | this.severity = Severity.INFO 21 | } 22 | 23 | override fun visitCreateTable(createStmt: CreateTable, context: RuleContext, callback: IssueEmit) { 24 | if (createStmt.columnDefinitions != null) { 25 | if (createStmt.columnDefinitions.size >= maxColumnSize) { 26 | callback(this, IssuePosition()) 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /rule-linter/rule-sql/src/main/kotlin/org/archguard/linter/rule/sql/rules/create/LimitTableNameLengthRule.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.linter.rule.sql.rules.create 2 | 3 | import net.sf.jsqlparser.statement.create.table.CreateTable 4 | import org.archguard.linter.rule.sql.SqlRule 5 | import org.archguard.rule.core.IssueEmit 6 | import org.archguard.rule.core.IssuePosition 7 | import org.archguard.rule.core.RuleContext 8 | import org.archguard.rule.core.Severity 9 | 10 | private const val TABLE_LENGTH = 32 11 | 12 | class LimitTableNameLengthRule : SqlRule() { 13 | init { 14 | this.id = "limit-table-name-length" 15 | this.name = "LimitTableNameLength" 16 | this.key = this.javaClass.name 17 | this.description = "表名应该小于 32 个字符" 18 | this.severity = Severity.INFO 19 | } 20 | 21 | override fun visitCreateTable(createStmt: CreateTable, context: RuleContext, callback: IssueEmit) { 22 | if (createStmt.table.name.length >= TABLE_LENGTH) { 23 | callback(this, IssuePosition()) 24 | } 25 | } 26 | } 27 | 28 | -------------------------------------------------------------------------------- /rule-linter/rule-sql/src/main/kotlin/org/archguard/linter/rule/sql/rules/create/SnakeCaseNamingRule.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.linter.rule.sql.rules.create 2 | 3 | import net.sf.jsqlparser.statement.create.table.CreateTable 4 | import org.archguard.linter.rule.sql.SqlRule 5 | import org.archguard.rule.core.IssueEmit 6 | import org.archguard.rule.core.IssuePosition 7 | import org.archguard.rule.core.RuleContext 8 | import org.archguard.rule.core.Severity 9 | import org.archguard.rule.common.Casing 10 | 11 | class SnakeCaseNamingRule : SqlRule() { 12 | init { 13 | this.id = "snake-case-naming" 14 | this.name = "SnakeCaseNaming" 15 | this.key = this.javaClass.name 16 | this.description = "表名应该使用 _ 来命名。" 17 | this.severity = Severity.INFO 18 | } 19 | 20 | override fun visitCreateTable(createStmt: CreateTable, context: RuleContext, callback: IssueEmit) { 21 | if (!Casing.is_nake(createStmt.table.name)) { 22 | callback(this, IssuePosition()) 23 | } 24 | 25 | if (createStmt.columns != null) { 26 | createStmt.columns.forEach { 27 | if (!Casing.is_nake(it)) { 28 | callback(this, IssuePosition()) 29 | } 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /rule-linter/rule-sql/src/main/kotlin/org/archguard/linter/rule/sql/rules/expression/LimitJoinsRule.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.linter.rule.sql.rules.expression 2 | 3 | import net.sf.jsqlparser.statement.select.Join 4 | import org.archguard.linter.rule.sql.SqlRule 5 | import org.archguard.rule.core.IssueEmit 6 | import org.archguard.rule.core.IssuePosition 7 | import org.archguard.rule.core.RuleContext 8 | import org.archguard.rule.core.Severity 9 | 10 | class LimitJoinsRule : SqlRule() { 11 | init { 12 | this.id = "limit-joins" 13 | this.name = "LimitJoins" 14 | this.key = this.javaClass.name 15 | this.description = "建议 JOIN 的表不要超过 5 个,JOIN 多表查询比较耗时时间,关联的表越多越耗时间,防止执行超时或死锁。" 16 | this.severity = Severity.BLOCKER 17 | } 18 | 19 | override fun visitJoinsExpr(joins: List, context: RuleContext, callback: IssueEmit) { 20 | if(joins.size >= 5) { 21 | callback(this, IssuePosition()) 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /rule-linter/rule-sql/src/main/kotlin/org/archguard/linter/rule/sql/rules/insert/InsertWithoutField.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.linter.rule.sql.rules.insert 2 | 3 | import net.sf.jsqlparser.statement.insert.Insert 4 | import org.archguard.linter.rule.sql.SqlRule 5 | import org.archguard.rule.core.IssueEmit 6 | import org.archguard.rule.core.IssuePosition 7 | import org.archguard.rule.core.RuleContext 8 | import org.archguard.rule.core.Severity 9 | 10 | class InsertWithoutField : SqlRule() { 11 | init { 12 | this.id = "insert-without-field" 13 | this.name = "InsertWithoutField" 14 | this.key = this.javaClass.name 15 | this.description = "INSERT 应该包含字段键名。" 16 | this.message = "正确示例:`INSERT INTO system (`name`) VALUES ('archguard');`\n" 17 | this.severity = Severity.BLOCKER 18 | } 19 | 20 | override fun visitInsert(insert: Insert, context: RuleContext, callback: IssueEmit) { 21 | if (insert.columns == null) { 22 | callback(this, IssuePosition()) 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /rule-linter/rule-sql/src/main/resources/META-INF/services/org.archguard.rule.core.RuleSetProvider: -------------------------------------------------------------------------------- 1 | org.archguard.linter.rule.sql.SqlRuleSetProvider -------------------------------------------------------------------------------- /rule-linter/rule-sql/src/main/resources/META-INF/services/org.archguard.rule.core.RuleVisitor: -------------------------------------------------------------------------------- 1 | org.archguard.linter.rule.sql.SqlRuleVisitor -------------------------------------------------------------------------------- /rule-linter/rule-test-code/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | kotlin("jvm") version "1.6.10" 3 | kotlin("plugin.serialization") version "1.6.10" 4 | } 5 | 6 | dependencies { 7 | api(project(":rule-core")) 8 | 9 | api("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.2") 10 | 11 | implementation("com.phodal.chapi:chapi-domain:1.5.6") 12 | implementation("org.jetbrains.kotlin:kotlin-reflect:1.6.10") 13 | } 14 | -------------------------------------------------------------------------------- /rule-linter/rule-test-code/src/main/kotlin/org/archguard/linter/rule/testcode/TestSmellRuleSetProvider.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.linter.rule.testcode 2 | 3 | import org.archguard.linter.rule.testcode.rules.DuplicateAssertRule 4 | import org.archguard.linter.rule.testcode.rules.EmptyTestRule 5 | import org.archguard.linter.rule.testcode.rules.NoIgnoreTestRule 6 | import org.archguard.linter.rule.testcode.rules.RedundantAssertionRule 7 | import org.archguard.linter.rule.testcode.rules.RedundantPrintRule 8 | import org.archguard.linter.rule.testcode.rules.SleepyTestRule 9 | import org.archguard.linter.rule.testcode.rules.UnknownTestRule 10 | import org.archguard.rule.core.RuleSet 11 | import org.archguard.rule.core.RuleSetProvider 12 | import org.archguard.rule.core.RuleType 13 | 14 | /* 15 | * Low level provider 16 | */ 17 | class TestSmellRuleSetProvider: RuleSetProvider { 18 | override fun get(): RuleSet { 19 | return RuleSet( 20 | RuleType.CHANGE_SMELL, 21 | "normal", 22 | EmptyTestRule(), 23 | NoIgnoreTestRule(), 24 | SleepyTestRule(), 25 | RedundantPrintRule(), 26 | RedundantAssertionRule(), 27 | UnknownTestRule(), 28 | DuplicateAssertRule(), 29 | ) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /rule-linter/rule-test-code/src/main/kotlin/org/archguard/linter/rule/testcode/rules/DuplicateAssertRule.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.linter.rule.testcode.rules 2 | 3 | import chapi.domain.core.CodeFunction 4 | import org.archguard.linter.rule.testcode.TbsRule 5 | import org.archguard.linter.rule.testcode.smellPosition 6 | import org.archguard.rule.core.IssueEmit 7 | import org.archguard.rule.core.Severity 8 | 9 | private const val MAX_ASSERTS = 5 10 | 11 | class DuplicateAssertRule : TbsRule() { 12 | init { 13 | this.id = "duplicated-assert" 14 | this.name = "DuplicateAssertTest" 15 | this.key = this.javaClass.name 16 | this.description = "包含了过多 Assert 语句的测试用例" 17 | this.message = "建议每个测试用例聚焦于一个测试场景和目的,不要企图编写一个各种场景面面俱到的巨无霸测试,这将让后期的维护更加困难" 18 | this.severity = Severity.WARN 19 | } 20 | 21 | override fun visitFunction(function: CodeFunction, index: Int, callback: IssueEmit) { 22 | if (function.FunctionCalls.isNotEmpty()) { 23 | val asserts = function.FunctionCalls.filter { isAssert(it) }.toList() 24 | if (asserts.size >= MAX_ASSERTS) { 25 | callback(this, function.Position.smellPosition()) 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /rule-linter/rule-test-code/src/main/kotlin/org/archguard/linter/rule/testcode/rules/EmptyTestRule.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.linter.rule.testcode.rules 2 | 3 | import chapi.domain.core.CodeFunction 4 | import org.archguard.rule.core.Severity 5 | import org.archguard.rule.core.IssueEmit 6 | import org.archguard.linter.rule.testcode.TbsRule 7 | import org.archguard.linter.rule.testcode.smellPosition 8 | 9 | class EmptyTestRule: TbsRule() { 10 | init { 11 | this.id = "empty-test" 12 | this.name = "EmptyTest" 13 | this.key = this.javaClass.name 14 | this.description = "Test is without any code" 15 | this.severity = Severity.WARN 16 | } 17 | 18 | override fun visitFunction(function: CodeFunction, index: Int, callback: IssueEmit) { 19 | if(function.isJUnitTest() && function.FunctionCalls.isEmpty()) { 20 | callback(this, function.Position.smellPosition()) 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /rule-linter/rule-test-code/src/main/kotlin/org/archguard/linter/rule/testcode/rules/NoIgnoreTestRule.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.linter.rule.testcode.rules 2 | 3 | import chapi.domain.core.CodeAnnotation 4 | import chapi.domain.core.CodeFunction 5 | import org.archguard.rule.core.Severity 6 | import org.archguard.rule.core.IssueEmit 7 | import org.archguard.linter.rule.testcode.TbsRule 8 | import org.archguard.linter.rule.testcode.smellPosition 9 | 10 | class NoIgnoreTestRule : TbsRule() { 11 | init { 12 | this.id = "no-ignore-test" 13 | this.name = "IgnoreTest" 14 | this.key = this.javaClass.name 15 | this.description = "被忽略(Ignore、Disabled)的测试用例" 16 | this.message = "当需求修改导致测试用例失败、失效了,应该尽快修复或移除而不是忽略。" 17 | this.severity = Severity.WARN 18 | } 19 | 20 | override fun visitFunctionAnnotation(function: CodeFunction, annotation: CodeAnnotation, index: Int, callback: IssueEmit) { 21 | if (annotation.Name == "Ignore" || annotation.Name == "Disabled") { 22 | callback(this, function.Position.smellPosition()) 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /rule-linter/rule-test-code/src/main/kotlin/org/archguard/linter/rule/testcode/rules/RedundantAssertionRule.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.linter.rule.testcode.rules 2 | 3 | import chapi.domain.core.CodeCall 4 | import chapi.domain.core.CodeFunction 5 | import org.archguard.rule.core.Severity 6 | import org.archguard.rule.core.IssueEmit 7 | import org.archguard.linter.rule.testcode.TbsRule 8 | import org.archguard.linter.rule.testcode.smellPosition 9 | 10 | 11 | class RedundantAssertionRule : TbsRule() { 12 | init { 13 | this.id = "redundant-assertion" 14 | this.name = "RedundantAssertionTest" 15 | this.key = this.javaClass.name 16 | this.description = "The test is contains invalid assert, like assertEquals(true, true)" 17 | this.severity = Severity.WARN 18 | } 19 | 20 | override fun visitFunctionCall(function: CodeFunction, codeCall: CodeCall, index: Int, callback: IssueEmit) { 21 | val assertParametersSize = 2 22 | if (isAssert(codeCall)) { 23 | if (codeCall.Parameters.size == assertParametersSize) { 24 | if (codeCall.Parameters[0].TypeValue == codeCall.Parameters[1].TypeValue) { 25 | callback(this, codeCall.Position.smellPosition()) 26 | } 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /rule-linter/rule-test-code/src/main/kotlin/org/archguard/linter/rule/testcode/rules/RedundantPrintRule.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.linter.rule.testcode.rules 2 | 3 | import chapi.domain.core.CodeCall 4 | import chapi.domain.core.CodeFunction 5 | import org.archguard.rule.core.Severity 6 | import org.archguard.rule.core.IssueEmit 7 | import org.archguard.rule.common.Language 8 | import org.archguard.linter.rule.testcode.TbsRule 9 | import org.archguard.linter.rule.testcode.smellPosition 10 | 11 | class RedundantPrintRule : TbsRule() { 12 | init { 13 | this.id = "redundant-print" 14 | this.name = "RedundantPrintTest" 15 | this.key = this.javaClass.name 16 | this.description = "包含了过多调试打印信息的测试用例" 17 | this.message = "自动化测试用例中,应该使用自动的 Assert 语句,替代需要人眼观察的 Print" 18 | this.severity = Severity.WARN 19 | } 20 | 21 | override fun visitFunctionCall(function: CodeFunction, codeCall: CodeCall, index: Int, callback: IssueEmit) { 22 | when(this.language) { 23 | Language.JAVA -> { 24 | if (codeCall.NodeName == "System.out" && (codeCall.FunctionName == "println" || codeCall.FunctionName == "printf" || codeCall.FunctionName == "print")) { 25 | callback(this, codeCall.Position.smellPosition()) 26 | } 27 | } 28 | else -> {} 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /rule-linter/rule-test-code/src/main/kotlin/org/archguard/linter/rule/testcode/rules/SleepyTestRule.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.linter.rule.testcode.rules 2 | 3 | import chapi.domain.core.CodeCall 4 | import chapi.domain.core.CodeFunction 5 | import org.archguard.rule.core.Severity 6 | import org.archguard.rule.core.IssueEmit 7 | import org.archguard.linter.rule.testcode.TbsRule 8 | import org.archguard.linter.rule.testcode.smellPosition 9 | 10 | class SleepyTestRule : TbsRule() { 11 | init { 12 | this.id = "sleep-test" 13 | this.name = "SleepyTest" 14 | this.key = this.javaClass.name 15 | this.description = "测试用例中包含 Sleep 休眠语句,常见于异步测试场景,或为了规避不同测试用例中某些操作的依赖和冲突。" 16 | this.message = "如 Robert C. Martin 在《代码整洁之道》所说的那样,好的测试应该是快速(Fast)、独立(Indendent)、可重复(Repeatable)、自足验证(Self-Validating)、及时(Timely)的\n" + 17 | " · 测试用例本身编写时,应该注意保持独立性,不同用例之前不要产生互相依赖、等待,尤其是不同用例使用的测试数据应该独立。\n" + 18 | " · 当处理异步测试场景时,建议使用 CompletableFuture 配合 CountDownLatch 的方式进行,从而不用硬编码休眠的时长。" 19 | this.severity = Severity.WARN 20 | } 21 | 22 | override fun visitFunctionCall(function: CodeFunction, codeCall: CodeCall, index: Int, callback: IssueEmit) { 23 | if (codeCall.FunctionName == "sleep" && codeCall.NodeName == "Thread") { 24 | callback(this, codeCall.Position.smellPosition()) 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /rule-linter/rule-test-code/src/main/kotlin/org/archguard/linter/rule/testcode/rules/UnknownTestRule.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.linter.rule.testcode.rules 2 | 3 | import chapi.domain.core.CodeCall 4 | import chapi.domain.core.CodeFunction 5 | import org.archguard.rule.core.Severity 6 | import org.archguard.rule.core.IssueEmit 7 | import org.archguard.linter.rule.testcode.TbsRule 8 | import org.archguard.linter.rule.testcode.smellPosition 9 | 10 | class UnknownTestRule : TbsRule() { 11 | private var hasAssert: Boolean = false 12 | 13 | init { 14 | this.id = "unknown-test" 15 | this.name = "UnknownTest" 16 | this.key = this.javaClass.name 17 | this.description = "缺乏了自动校验的测试用例,这将无法达到自动验证结果的目的。" 18 | this.message = "为每个测试用例都添加足够的自动校验 Assert 语句" 19 | this.severity = Severity.WARN 20 | } 21 | 22 | override fun visitFunctionCall(function: CodeFunction, codeCall: CodeCall, index: Int, callback: IssueEmit) { 23 | if(isAssert(codeCall)) { 24 | this.hasAssert = true 25 | } 26 | } 27 | 28 | override fun beforeVisitFunction(function: CodeFunction, callback: IssueEmit) { 29 | this.hasAssert = false 30 | } 31 | 32 | override fun afterVisitFunction(function: CodeFunction, callback: IssueEmit) { 33 | if(!this.hasAssert) { 34 | callback(this, function.Position.smellPosition()) 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /rule-linter/rule-test-code/src/main/resources/META-INF/services/org.archguard.rule.core.RuleSetProvider: -------------------------------------------------------------------------------- 1 | org.archguard.linter.rule.testcode.TestSmellRuleSetProvider -------------------------------------------------------------------------------- /rule-linter/rule-test-code/src/main/resources/META-INF/services/org.archguard.rule.core.RuleVisitor: -------------------------------------------------------------------------------- 1 | org.archguard.linter.rule.testcode.TestSmellRuleVisitor -------------------------------------------------------------------------------- /rule-linter/rule-webapi/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | kotlin("jvm") version "1.6.10" 3 | kotlin("plugin.serialization") version "1.6.10" 4 | } 5 | 6 | dependencies { 7 | api(project(":rule-core")) 8 | // todo: thinking remove 9 | api(project(":scanner_core")) 10 | 11 | api("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.2") 12 | 13 | implementation("com.phodal.chapi:chapi-domain:1.5.6") 14 | implementation("org.jetbrains.kotlin:kotlin-reflect:1.6.10") 15 | } 16 | -------------------------------------------------------------------------------- /rule-linter/rule-webapi/src/main/kotlin/org/archguard/linter/rule/webapi/WebApiRule.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.linter.rule.webapi 2 | 3 | import org.archguard.rule.core.IssueEmit 4 | import org.archguard.rule.core.Rule 5 | import org.archguard.rule.core.RuleContext 6 | import org.archguard.scanner.core.sourcecode.ContainerResource 7 | 8 | open class WebApiRule : Rule() { 9 | open fun visitResources(resources: List, context: RuleContext, callback: IssueEmit) { 10 | resources.forEach { 11 | this.visitResource(it, context, callback) 12 | } 13 | } 14 | 15 | open fun visitResource(resource: ContainerResource, context: RuleContext, callback: IssueEmit) { 16 | resource.sourceUrl.split("/").forEach { 17 | this.visitSegment(it, context, callback) 18 | } 19 | } 20 | 21 | open fun visitSegment(it: String, context: RuleContext, callback: IssueEmit) { 22 | 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /rule-linter/rule-webapi/src/main/kotlin/org/archguard/linter/rule/webapi/WebApiRuleSetProvider.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.linter.rule.webapi 2 | 3 | import org.archguard.rule.core.RuleSet 4 | import org.archguard.rule.core.RuleSetProvider 5 | import org.archguard.rule.core.RuleType 6 | import org.archguard.linter.rule.webapi.rules.MultipleParametersRule 7 | import org.archguard.linter.rule.webapi.rules.MinFeatureApiRule 8 | import org.archguard.linter.rule.webapi.rules.NoCrudEndRule 9 | import org.archguard.linter.rule.webapi.rules.NoHttpMethodInUrlRule 10 | import org.archguard.linter.rule.webapi.rules.NotUppercaseRule 11 | import org.archguard.linter.rule.webapi.rules.StartWithoutCrudRule 12 | import org.archguard.linter.rule.webapi.rules.SpliceNamingRule 13 | 14 | class WebApiRuleSetProvider: RuleSetProvider { 15 | override fun get(): RuleSet { 16 | return RuleSet( 17 | RuleType.CHANGE_SMELL, 18 | "normal", 19 | SpliceNamingRule(), 20 | NoCrudEndRule(), 21 | NotUppercaseRule(), 22 | StartWithoutCrudRule(), 23 | NoHttpMethodInUrlRule(), 24 | MinFeatureApiRule(), 25 | MultipleParametersRule(), 26 | ) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /rule-linter/rule-webapi/src/main/kotlin/org/archguard/linter/rule/webapi/WebApiRuleVisitor.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.linter.rule.webapi 2 | 3 | import org.archguard.scanner.core.sourcecode.ContainerResource 4 | import org.archguard.rule.core.Issue 5 | import org.archguard.rule.core.IssuePosition 6 | import org.archguard.rule.core.Rule 7 | import org.archguard.rule.core.RuleContext 8 | import org.archguard.rule.core.RuleSet 9 | import org.archguard.rule.core.RuleType 10 | import org.archguard.rule.core.RuleVisitor 11 | 12 | class WebApiRuleVisitor(private val resources: List) : RuleVisitor(resources) { 13 | override fun visitor(ruleSets: Iterable): List { 14 | val results: MutableList = mutableListOf() 15 | val context = RuleContext() 16 | 17 | ruleSets.forEach { ruleSet -> 18 | ruleSet.rules.forEach { rule -> 19 | // todo: cast by plugins 20 | val apiRule = rule as WebApiRule 21 | resources.map { 22 | apiRule.visitResources(this.resources, context, fun(rule: Rule, position: IssuePosition) { 23 | results += Issue( 24 | position, 25 | ruleId = rule.key, 26 | name = rule.name, 27 | detail = rule.description, 28 | ruleType = RuleType.HTTP_API_SMELL 29 | ) 30 | }) 31 | } 32 | } 33 | } 34 | 35 | return results 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /rule-linter/rule-webapi/src/main/kotlin/org/archguard/linter/rule/webapi/rules/Constants.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.linter.rule.webapi.rules 2 | 3 | var CREATE_OPS = arrayOf("post", "create", "put") 4 | var GET_OPS = arrayOf("get", "fetch") 5 | 6 | val CRUD = arrayOf("create", "update", "refresh", "delete", "get", "put", "set") 7 | -------------------------------------------------------------------------------- /rule-linter/rule-webapi/src/main/kotlin/org/archguard/linter/rule/webapi/rules/MinFeatureApiRule.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.linter.rule.webapi.rules 2 | 3 | import org.archguard.rule.core.IssueEmit 4 | import org.archguard.rule.core.IssuePosition 5 | import org.archguard.rule.core.RuleContext 6 | import org.archguard.rule.core.Severity 7 | import org.archguard.linter.rule.webapi.WebApiRule 8 | 9 | class MinFeatureApiRule : WebApiRule() { 10 | init { 11 | this.id = "min-feature" 12 | this.name = "MinFeature" 13 | this.key = this.javaClass.name 14 | this.description = "API 应该保持单一职责的原则,一个 API 只做一件事。" 15 | this.message = "> 让每个程序只做好一件事。要完成一项工作,构造全新的比在复杂的旧程序里添加新特性更好。 —— McIlroy, Pinson 和 Tague。\n" + 16 | "\n" + 17 | "—— 《Google 系统架构解密:构建安全可靠的系统》\n" 18 | this.severity = Severity.INFO 19 | } 20 | 21 | override fun visitSegment(it: String, context: RuleContext, callback: IssueEmit) { 22 | if (it.contains("-and-") || it.contains("-with-")) { 23 | callback(this, IssuePosition()) 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /rule-linter/rule-webapi/src/main/kotlin/org/archguard/linter/rule/webapi/rules/MultipleParametersRule.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.linter.rule.webapi.rules 2 | 3 | import org.archguard.rule.core.IssueEmit 4 | import org.archguard.rule.core.IssuePosition 5 | import org.archguard.rule.core.RuleContext 6 | import org.archguard.rule.core.Severity 7 | import org.archguard.linter.rule.webapi.WebApiRule 8 | import org.archguard.scanner.core.sourcecode.ContainerResource 9 | 10 | class MultipleParametersRule : WebApiRule() { 11 | init { 12 | this.id = "multiple-parameters" 13 | this.name = "MultipleParameters" 14 | this.key = this.javaClass.name 15 | this.description = "URL 中的参数不宜超过 3 个,可以放到 body 中。错误示例:/api/book/{bookType}/{bookId}/{bookChildType}/{childId}" 16 | this.severity = Severity.INFO 17 | } 18 | 19 | override fun visitResource(resource: ContainerResource, context: RuleContext, callback: IssueEmit) { 20 | var paramsCount = 0 21 | resource.sourceUrl.split("/").forEach { 22 | if(it.startsWith("{") && it.endsWith("}")) { 23 | paramsCount++ 24 | } 25 | } 26 | 27 | if(paramsCount >= 3) { 28 | callback(this, IssuePosition()) 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /rule-linter/rule-webapi/src/main/kotlin/org/archguard/linter/rule/webapi/rules/NoCrudEnd.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.linter.rule.webapi.rules 2 | 3 | import org.archguard.rule.core.IssueEmit 4 | import org.archguard.rule.core.IssuePosition 5 | import org.archguard.rule.core.RuleContext 6 | import org.archguard.rule.core.Severity 7 | import org.archguard.linter.rule.webapi.WebApiRule 8 | import org.archguard.scanner.core.sourcecode.ContainerResource 9 | 10 | class NoCrudEndRule: WebApiRule() { 11 | init { 12 | this.id = "no-crud-end" 13 | this.name = "NoCrudEndRule" 14 | this.key = this.javaClass.name 15 | this.description = "URL 不应该以 CRUD 结尾,错误的方式 `/api/book/get`,正确的方式: `GET /api/book`" 16 | this.severity = Severity.WARN 17 | } 18 | 19 | override fun visitResource(resource: ContainerResource, context: RuleContext, callback: IssueEmit) { 20 | val split = resource.sourceUrl.split("/") 21 | if(CRUD.contains(split.last().lowercase())) { 22 | callback(this, IssuePosition()) 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /rule-linter/rule-webapi/src/main/kotlin/org/archguard/linter/rule/webapi/rules/NoHttpMethodInUrlRule.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.linter.rule.webapi.rules 2 | 3 | import org.archguard.rule.core.IssueEmit 4 | import org.archguard.rule.core.IssuePosition 5 | import org.archguard.rule.core.RuleContext 6 | import org.archguard.rule.core.Severity 7 | import org.archguard.linter.rule.webapi.WebApiRule 8 | import org.archguard.scanner.core.sourcecode.ContainerResource 9 | 10 | class NoHttpMethodInUrlRule : WebApiRule() { 11 | init { 12 | this.id = "no-http-method-in-url" 13 | this.name = "NoHttpMethodInUrl" 14 | this.key = this.javaClass.name 15 | this.description = "URL 中不应该包含 CRUD 方法。" 16 | this.severity = Severity.WARN 17 | } 18 | 19 | override fun visitResource(resource: ContainerResource, context: RuleContext, callback: IssueEmit) { 20 | val split = resource.sourceUrl.split("/") 21 | 22 | split.map { 23 | if (CRUD.contains(it)) { 24 | callback(this, IssuePosition()) 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /rule-linter/rule-webapi/src/main/kotlin/org/archguard/linter/rule/webapi/rules/NotUppercaseRule.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.linter.rule.webapi.rules 2 | 3 | import org.archguard.rule.core.IssueEmit 4 | import org.archguard.rule.core.IssuePosition 5 | import org.archguard.rule.core.RuleContext 6 | import org.archguard.rule.core.Severity 7 | import org.archguard.linter.rule.webapi.WebApiRule 8 | import org.archguard.scanner.core.sourcecode.ContainerResource 9 | 10 | private val HAS_UPPERCASE_RULE = ".*[A-Z].*".toRegex() 11 | private val PARAMETER_IN_URL = "\\{[a-zA-Z?:]+\\}".toRegex() 12 | 13 | class NotUppercaseRule: WebApiRule() { 14 | init { 15 | this.id = "not-uppercase" 16 | this.name = "NotUppercaseRule" 17 | this.key = this.javaClass.name 18 | this.description = "URL 中不应该包含大写字符。" 19 | this.severity = Severity.WARN 20 | } 21 | 22 | override fun visitResource(resource: ContainerResource, context: RuleContext, callback: IssueEmit) { 23 | val split = resource.sourceUrl.split("/") 24 | split.forEach { 25 | if(HAS_UPPERCASE_RULE.matches(it) && !PARAMETER_IN_URL.matches(it)) { 26 | callback(this, IssuePosition()) 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /rule-linter/rule-webapi/src/main/kotlin/org/archguard/linter/rule/webapi/rules/SpliceNamingRule.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.linter.rule.webapi.rules 2 | 3 | import org.archguard.rule.core.IssueEmit 4 | import org.archguard.rule.core.IssuePosition 5 | import org.archguard.rule.core.RuleContext 6 | import org.archguard.rule.core.Severity 7 | import org.archguard.scanner.core.sourcecode.ContainerResource 8 | import org.archguard.linter.rule.webapi.WebApiRule 9 | 10 | private const val MAX_URL_NODE_LENGTH = 20 11 | private val CHAR_REGEX = "[a-zA-Z]+".toRegex() 12 | 13 | class SpliceNamingRule : WebApiRule() { 14 | init { 15 | this.id = "splice-naming" 16 | this.name = "SpliceNamingRule" 17 | this.key = this.javaClass.name 18 | this.description = "API 应该采用 - 的方式命名,单个资源的长度通常不超过 20 字符。" 19 | this.severity = Severity.WARN 20 | } 21 | 22 | override fun visitResource(resource: ContainerResource, context: RuleContext, callback: IssueEmit) { 23 | resource.sourceUrl.split("/").forEach { 24 | if(CHAR_REGEX.matches(it) && it.length >= MAX_URL_NODE_LENGTH) { 25 | callback(this, IssuePosition()) 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /rule-linter/rule-webapi/src/main/kotlin/org/archguard/linter/rule/webapi/rules/StartWithoutCrudRule.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.linter.rule.webapi.rules 2 | 3 | import org.archguard.rule.core.IssueEmit 4 | import org.archguard.rule.core.IssuePosition 5 | import org.archguard.rule.core.RuleContext 6 | import org.archguard.rule.core.Severity 7 | import org.archguard.linter.rule.webapi.WebApiRule 8 | import org.archguard.scanner.core.sourcecode.ContainerResource 9 | 10 | class StartWithoutCrudRule : WebApiRule() { 11 | init { 12 | this.id = "start-without-crud" 13 | this.name = "StartWithoutCrudRule" 14 | this.key = this.javaClass.name 15 | this.description = "URL 不应该以 CRUD 开头。错误示例: `/api/getbook`, 正确示例: `GET /api/book`" 16 | this.severity = Severity.WARN 17 | } 18 | 19 | override fun visitResource(resource: ContainerResource, context: RuleContext, callback: IssueEmit) { 20 | val split = resource.sourceUrl.split("/") 21 | split.forEach { node -> 22 | CRUD.forEach { 23 | if (node != it && node.lowercase().startsWith(it)) { 24 | callback(this, IssuePosition()) 25 | } 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /rule-linter/rule-webapi/src/main/resources/META-INF/services/org.archguard.rule.core.RuleSetProvider: -------------------------------------------------------------------------------- 1 | org.archguard.linter.rule.webapi.WebApiRuleSetProvider -------------------------------------------------------------------------------- /rule-linter/rule-webapi/src/main/resources/META-INF/services/org.archguard.rule.core.RuleVisitor: -------------------------------------------------------------------------------- 1 | org.archguard.linter.rule.webapi.WebApiRuleVisitor -------------------------------------------------------------------------------- /scanner_cli/.gitignore: -------------------------------------------------------------------------------- 1 | dependencies/analysers/* 2 | 3 | localtester.sh 4 | -------------------------------------------------------------------------------- /scanner_cli/README.md: -------------------------------------------------------------------------------- 1 | ## scanner cli 2 | 3 | 全权(规划中)接收archguard的扫描请求, 并将结果发送到archguard的服务器. 4 | 5 | - 判断执行条件 6 | - 拉取scanner lib, 包括自定义的 7 | - 执行计算并发送结果 8 | 9 | ### 后续 10 | 11 | 接收HTTP的扫描请求, 以实现分布式运行 12 | 拆分和规整已有的scanner 13 | -------------------------------------------------------------------------------- /scanner_cli/src/main/kotlin/org/archguard/scanner/ctl/HttpController.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.ctl 2 | 3 | import org.archguard.scanner.ctl.command.ScannerCommand 4 | import org.archguard.scanner.ctl.loader.AnalyserDispatcher 5 | 6 | // TODO set up a http server to accept scanner command 7 | interface HttpController { 8 | fun execute(command: ScannerCommand) { 9 | AnalyserDispatcher().dispatch(command) 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /scanner_cli/src/main/kotlin/org/archguard/scanner/ctl/client/ChainedArchGuardClient.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.ctl.client 2 | 3 | import chapi.domain.core.CodeDataStruct 4 | import org.archguard.scanner.core.client.ArchGuardClient 5 | import org.archguard.scanner.core.diffchanges.ChangedCall 6 | import org.archguard.scanner.core.git.GitLogs 7 | import org.archguard.scanner.core.sca.CompositionDependency 8 | import org.archguard.scanner.core.sourcecode.CodeDatabaseRelation 9 | import org.archguard.scanner.core.sourcecode.ContainerService 10 | import org.archguard.scanner.ctl.command.ScannerCommand 11 | 12 | class ChainedArchGuardClient( 13 | private val clients: List, 14 | ) : ArchGuardClient { 15 | override fun saveDataStructure(codes: List) = clients.forEach { it.saveDataStructure(codes) } 16 | override fun saveApi(apis: List) = clients.forEach { it.saveApi(apis) } 17 | override fun saveRelation(records: List) = clients.forEach { it.saveRelation(records) } 18 | override fun saveGitLogs(gitLogs: GitLogs) = clients.forEach { it.saveGitLogs(gitLogs) } 19 | override fun saveDiffs(calls: List) = clients.forEach { it.saveDiffs(calls) } 20 | override fun saveDependencies(dependencies: List) = 21 | clients.forEach { it.saveDependencies(dependencies) } 22 | } 23 | -------------------------------------------------------------------------------- /scanner_cli/src/main/kotlin/org/archguard/scanner/ctl/impl/CliDiffChangesContext.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.ctl.impl 2 | 3 | import org.archguard.scanner.core.client.ArchGuardClient 4 | import org.archguard.scanner.core.diffchanges.DiffChangesContext 5 | 6 | data class CliDiffChangesContext( 7 | override val client: ArchGuardClient, 8 | override val path: String, 9 | override val branch: String, 10 | override val since: String, 11 | override val until: String, 12 | override val depth: Int, 13 | ) : DiffChangesContext 14 | -------------------------------------------------------------------------------- /scanner_cli/src/main/kotlin/org/archguard/scanner/ctl/impl/CliGitContext.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.ctl.impl 2 | 3 | import org.archguard.scanner.core.client.ArchGuardClient 4 | import org.archguard.scanner.core.git.GitContext 5 | 6 | data class CliGitContext( 7 | override val client: ArchGuardClient, 8 | override val path: String, 9 | override val repoId: String, 10 | override val branch: String, 11 | override val startedAt: Long, 12 | ) : GitContext 13 | -------------------------------------------------------------------------------- /scanner_cli/src/main/kotlin/org/archguard/scanner/ctl/impl/CliScaContext.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.ctl.impl 2 | 3 | import org.archguard.scanner.core.client.ArchGuardClient 4 | import org.archguard.scanner.core.sca.ScaContext 5 | 6 | data class CliScaContext( 7 | override val client: ArchGuardClient, 8 | override val path: String, 9 | override val language: String, 10 | ) : ScaContext 11 | -------------------------------------------------------------------------------- /scanner_cli/src/main/kotlin/org/archguard/scanner/ctl/impl/CliSourceCodeContext.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.ctl.impl 2 | 3 | import org.archguard.scanner.core.client.ArchGuardClient 4 | import org.archguard.scanner.core.sourcecode.SourceCodeContext 5 | 6 | data class CliSourceCodeContext( 7 | override val language: String, 8 | override val features: List, 9 | override val client: ArchGuardClient, 10 | override val path: String, 11 | ) : SourceCodeContext 12 | -------------------------------------------------------------------------------- /scanner_cli/src/main/kotlin/org/archguard/scanner/ctl/impl/OfficialAnalyserSpecs.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.ctl.impl 2 | 3 | import org.archguard.scanner.core.AnalyserSpec 4 | 5 | private const val VERSION = "2.0.0-alpha.7" 6 | private const val TAG = "v$VERSION" 7 | private const val RELEASE_REPO_URL = "https://github.com/archguard/scanner/releases/download/$TAG" 8 | 9 | enum class OfficialAnalyserSpecs( 10 | private val className: String, 11 | ) { 12 | // languages 13 | CSHARP("CSharpAnalyser"), 14 | GO("GoAnalyser"), 15 | JAVA("JavaAnalyser"), 16 | KOTLIN("KotlinAnalyser"), 17 | PYTHON("PythonAnalyser"), 18 | SCALA("ScalaAnalyser"), 19 | TYPESCRIPT("TypeScriptAnalyser"), 20 | JAVASCRIPT(TYPESCRIPT.className), 21 | 22 | // features 23 | APICALLS("ApiCallAnalyser"), 24 | DATAMAP("DataMapAnalyser"), 25 | 26 | GIT("GitAnalyser"), 27 | SCA("ScaAnalyser"), 28 | DIFF_CHANGES("DiffChangesAnalyser"), 29 | ; 30 | 31 | fun spec() = AnalyserSpec(identifier(), RELEASE_REPO_URL, VERSION, jarFileName(), className) 32 | private fun identifier() = name.lowercase() 33 | private fun jarFileName(): String { 34 | val identifier = identifier() 35 | val prefix = when (this) { 36 | GIT, SCA, DIFF_CHANGES -> "analyser" 37 | DATAMAP, APICALLS -> "feat" 38 | else -> "lang" 39 | } 40 | return "${prefix}_$identifier-$VERSION-all.jar" 41 | } 42 | 43 | companion object { 44 | fun specs() = values().map(OfficialAnalyserSpecs::spec) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /scanner_cli/src/main/kotlin/org/archguard/scanner/ctl/loader/rule/RuleDispatcher.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.ctl.loader.rule 2 | 3 | import org.archguard.rule.core.Issue 4 | import org.archguard.rule.core.RuleSetProvider 5 | import org.archguard.rule.core.RuleVisitor 6 | import org.archguard.scanner.ctl.command.ScannerCommand 7 | 8 | /** 9 | * **RuleDispatcher** is to load rules 10 | */ 11 | class RuleDispatcher { 12 | fun dispatch(command: ScannerCommand) { 13 | 14 | } 15 | 16 | // todo: add disable rule checks 17 | fun executeOne(ruleVisitor: RuleVisitor, ruleSetProvider: RuleSetProvider): List { 18 | return ruleVisitor.visitor(listOf(ruleSetProvider.get())) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /scanner_cli/src/main/kotlin/org/archguard/scanner/ctl/loader/rule/RuleLoader.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.ctl.loader.rule 2 | 3 | import org.archguard.rule.core.RuleSetProvider 4 | import org.archguard.rule.core.RuleVisitor 5 | import java.io.File 6 | import java.net.URLClassLoader 7 | import java.util.ServiceLoader 8 | 9 | 10 | data class LinterSpec( 11 | val jar: String, 12 | var className: String, 13 | ) 14 | 15 | /** 16 | * **RuleLoader** is load ruleSets by classes 17 | */ 18 | object RuleLoader { 19 | fun load(data: List, spec: LinterSpec): Pair> { 20 | val jarUrl = File(spec.jar).toURI().toURL() 21 | val loader = URLClassLoader(arrayOf(jarUrl)) 22 | val ruleSetProviders = ServiceLoader.load(RuleSetProvider::class.java, loader).toList() 23 | val visitor = Class.forName(spec.className, true, loader) 24 | .declaredConstructors[0] 25 | .newInstance(data) as RuleVisitor 26 | 27 | return visitor to ruleSetProviders 28 | } 29 | 30 | fun loadRules(disabledRules: String) { 31 | // 1. load classes from jar 32 | val loader: ServiceLoader = ServiceLoader.load(RuleSetProvider::class.java) 33 | for (service in loader) { 34 | println("Log written by $service") 35 | } 36 | 37 | // 2. split disabled_rules 38 | 39 | // 3. filter RuleSetProvider 40 | 41 | // 4. filter disableRules with VisitorProvider 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /scanner_cli/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | [SCANNER] %msg%n 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /scanner_cli/src/test/kotlin/org/archguard/scanner/ctl/impl/OfficialAnalyserSpecsTest.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.ctl.impl 2 | 3 | import org.assertj.core.api.Assertions.assertThat 4 | import org.junit.jupiter.api.Test 5 | 6 | internal class OfficialAnalyserSpecsTest { 7 | @Test 8 | fun `should output the spec with the default jar for all the official analysers`() { 9 | assertThat(OfficialAnalyserSpecs.KOTLIN.spec().identifier).isEqualTo("kotlin") 10 | assertThat(OfficialAnalyserSpecs.APICALLS.spec().identifier).isEqualTo("apicalls") 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /scanner_cli/src/test/kotlin/org/archguard/scanner/ctl/loader/rule/RuleLoaderTest.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.ctl.loader.rule 2 | 3 | import org.archguard.scanner.core.sourcecode.ContainerResource 4 | import org.junit.jupiter.api.Test 5 | import kotlin.test.assertEquals 6 | 7 | internal class RuleLoaderTest { 8 | @Test 9 | internal fun load() { 10 | val jar = this.javaClass.classLoader.getResource("kotlin/testonly-rule-webapi-2.0.0-alpha.2.jar")!! 11 | 12 | val resource = ContainerResource(sourceUrl = "api/book/delete/{bookId}") 13 | val ruleName = "org.archguard.linter.rule.webapi.WebApiRuleVisitor" 14 | 15 | val (ruleVisitor, ruleSetProviders) = RuleLoader.load(listOf(resource), LinterSpec(jar.path, ruleName)) 16 | 17 | val issues = ruleVisitor.visitor(ruleSetProviders.map { it.get() }) 18 | 19 | assertEquals(1, ruleSetProviders.size) 20 | assertEquals(1, issues.size) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /scanner_cli/src/test/resources/kotlin/Hello.kt: -------------------------------------------------------------------------------- 1 | class Hello { 2 | fun sayHello() { 3 | println("Hello Kotlin!") 4 | } 5 | } 6 | 7 | fun main() { 8 | Hello().sayHello() 9 | } 10 | -------------------------------------------------------------------------------- /scanner_cli/src/test/resources/kotlin/testonly-lang_kotlin-1.6.1-all.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/archguard/scanner/c7723b67ef980af88c078da28c9d2927147daf7a/scanner_cli/src/test/resources/kotlin/testonly-lang_kotlin-1.6.1-all.jar -------------------------------------------------------------------------------- /scanner_cli/src/test/resources/kotlin/testonly-rule-webapi-2.0.0-alpha.2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/archguard/scanner/c7723b67ef980af88c078da28c9d2927147daf7a/scanner_cli/src/test/resources/kotlin/testonly-rule-webapi-2.0.0-alpha.2.jar -------------------------------------------------------------------------------- /scanner_cli/src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /scanner_core/README.md: -------------------------------------------------------------------------------- 1 | ## scanner core 2 | 3 | 所有静态扫描都来自于scanner, 数据来源包括但不限于: 源文件, git, ci, logs, etc. 4 | 5 | ### roadmap 6 | 7 | 1. input analyser call graph 8 | 9 | ```json 10 | [ 11 | { 12 | "name": "language", 13 | "impl": "kotlin" 14 | }, 15 | { 16 | "name": "apicalls", 17 | "dependencies": [ 18 | "language" 19 | ] 20 | }, 21 | { 22 | "name": "datamap", 23 | "dependencies": [ 24 | "language" 25 | ] 26 | }, 27 | { 28 | "name": "git" 29 | }, 30 | { 31 | "name": "diff_changes", 32 | "dependencies": [ 33 | "language", 34 | "git" 35 | ] 36 | } 37 | ] 38 | ``` 39 | 40 | 2. sort by dependency (有向无环图) 41 | 3. execute the diagram 42 | 43 | ``` 44 | read sourcecode -> language[kotlin].analyse() -> save to language.json (or put into cache[language]) 45 | read git logs -> git.analyse() -> save to git.json 46 | 47 | read language.json -> api_calls.analyse() -> save to api_calls.json 48 | read language.json -> datamap.analyse() -> save to datamap.json 49 | read language.json, git.json -> diff_changes.analyse() -> save to diff_changes.json 50 | ``` 51 | -------------------------------------------------------------------------------- /scanner_core/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | kotlin("jvm") version "1.6.10" 3 | kotlin("plugin.serialization") version "1.6.10" 4 | } 5 | 6 | dependencies { 7 | api("com.phodal.chapi:chapi-domain:1.5.6") 8 | api("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.2") 9 | api("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.1") 10 | 11 | testImplementation("io.mockk:mockk:1.12.3") 12 | testImplementation("org.assertj:assertj-core:3.22.0") 13 | } 14 | -------------------------------------------------------------------------------- /scanner_core/src/main/kotlin/org/archguard/scanner/core/Analyser.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.core 2 | 3 | import org.archguard.scanner.core.context.Context 4 | 5 | interface Analyser { 6 | val context: C 7 | } 8 | 9 | fun main() { 10 | println("Hello, analyser!") 11 | } 12 | -------------------------------------------------------------------------------- /scanner_core/src/main/kotlin/org/archguard/scanner/core/AnalyserSpec.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.core 2 | 3 | import kotlinx.serialization.Serializable 4 | 5 | @Serializable 6 | data class AnalyserSpec( 7 | val identifier: String, 8 | val host: String, 9 | val version: String, 10 | val jar: String, 11 | val className: String, // calculate via identifier?? 12 | ) 13 | -------------------------------------------------------------------------------- /scanner_core/src/main/kotlin/org/archguard/scanner/core/archtecture/CodeLanguage.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.core.archtecture 2 | 3 | class CodeLanguage( 4 | val name: String, 5 | val line: Int 6 | ) 7 | -------------------------------------------------------------------------------- /scanner_core/src/main/kotlin/org/archguard/scanner/core/client/ArchGuardClient.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.core.client 2 | 3 | import chapi.domain.core.CodeDataStruct 4 | import org.archguard.scanner.core.diffchanges.ChangedCall 5 | import org.archguard.scanner.core.git.GitLogs 6 | import org.archguard.scanner.core.sca.CompositionDependency 7 | import org.archguard.scanner.core.sourcecode.CodeDatabaseRelation 8 | import org.archguard.scanner.core.sourcecode.ContainerService 9 | 10 | // api of the archguard, scanner can communicate to server via this api with limited functions 11 | interface ArchGuardClient { 12 | fun saveDataStructure(codes: List) 13 | fun saveApi(apis: List) 14 | fun saveRelation(records: List) 15 | fun saveGitLogs(gitLogs: GitLogs) 16 | fun saveDiffs(calls: List) 17 | fun saveDependencies(dependencies: List) 18 | } 19 | -------------------------------------------------------------------------------- /scanner_core/src/main/kotlin/org/archguard/scanner/core/context/Context.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.core.context 2 | 3 | import org.archguard.scanner.core.client.ArchGuardClient 4 | 5 | // context of the scanner runtime, hold the data and the api 6 | interface Context { 7 | val type: AnalyserType 8 | val client: ArchGuardClient 9 | } 10 | 11 | enum class AnalyserType { 12 | SOURCE_CODE, 13 | GIT, 14 | DIFF_CHANGES, 15 | SCA, 16 | RULE, 17 | ; 18 | } 19 | 20 | -------------------------------------------------------------------------------- /scanner_core/src/main/kotlin/org/archguard/scanner/core/diffchanges/ChangedCall.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.core.diffchanges 2 | 3 | import kotlinx.serialization.Serializable 4 | 5 | @Serializable 6 | class ChangedCall( 7 | val path: String, 8 | val packageName: String, 9 | val className: String, 10 | val relations: List 11 | ) 12 | 13 | @Serializable 14 | class ChangeRelation( 15 | val source: String, 16 | val target: String 17 | ) 18 | -------------------------------------------------------------------------------- /scanner_core/src/main/kotlin/org/archguard/scanner/core/diffchanges/DiffChangesAnalyser.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.core.diffchanges 2 | 3 | import org.archguard.scanner.core.Analyser 4 | 5 | interface DiffChangesAnalyser : Analyser { 6 | fun analyse(): List 7 | } 8 | -------------------------------------------------------------------------------- /scanner_core/src/main/kotlin/org/archguard/scanner/core/diffchanges/DiffChangesContext.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.core.diffchanges 2 | 3 | import org.archguard.scanner.core.context.AnalyserType 4 | import org.archguard.scanner.core.context.Context 5 | 6 | interface DiffChangesContext : Context { 7 | override val type: AnalyserType get() = AnalyserType.DIFF_CHANGES 8 | 9 | val path: String 10 | val branch: String 11 | val since: String 12 | val until: String 13 | val depth: Int 14 | } 15 | -------------------------------------------------------------------------------- /scanner_core/src/main/kotlin/org/archguard/scanner/core/git/GitAnalyser.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.core.git 2 | 3 | import org.archguard.scanner.core.Analyser 4 | 5 | interface GitAnalyser : Analyser { 6 | fun analyse(): GitLogs 7 | } 8 | -------------------------------------------------------------------------------- /scanner_core/src/main/kotlin/org/archguard/scanner/core/git/GitContext.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.core.git 2 | 3 | import org.archguard.scanner.core.context.AnalyserType 4 | import org.archguard.scanner.core.context.Context 5 | 6 | interface GitContext : Context { 7 | override val type: AnalyserType get() = AnalyserType.GIT 8 | 9 | val path: String 10 | val repoId: String 11 | val branch: String 12 | val startedAt: Long 13 | } 14 | -------------------------------------------------------------------------------- /scanner_core/src/main/kotlin/org/archguard/scanner/core/git/GitLogs.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.core.git 2 | 3 | import kotlinx.serialization.Serializable 4 | 5 | @Serializable 6 | data class GitLogs( 7 | val commitLog: List, 8 | val changeEntry: List, 9 | val pathChangeCount: List 10 | ) 11 | 12 | @Serializable 13 | data class CommitLog( 14 | val id: String, 15 | val commitTime: Long, 16 | val shortMessage: String, 17 | val committerName: String, 18 | val committerEmail: String, 19 | val repositoryId: String, 20 | ) 21 | 22 | @Serializable 23 | data class ChangeEntry( 24 | val oldPath: String, 25 | val newPath: String, 26 | val commitTime: Long, 27 | val cognitiveComplexity: Int, 28 | val changeMode: String, 29 | val commitId: String, 30 | val committer: String, 31 | val lineAdded: Int, 32 | val lineDeleted: Int 33 | ) 34 | 35 | // todo: update branch info 36 | @Serializable 37 | data class GitBranch( 38 | val name: String, 39 | val lastModified: String = "", 40 | val lastRead: String = "", 41 | ) 42 | 43 | @Serializable 44 | data class PathChangeCount( 45 | val id: String, 46 | val path: String, 47 | val changes: Int, 48 | val lineCount: Long, 49 | val language: String, 50 | ) 51 | -------------------------------------------------------------------------------- /scanner_core/src/main/kotlin/org/archguard/scanner/core/sca/CompositionDependency.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.core.sca 2 | 3 | import kotlinx.serialization.Serializable 4 | 5 | @Serializable 6 | data class CompositionDependency( 7 | val id: String, 8 | val name: String, 9 | val path: String, 10 | val version: String, 11 | val parentId: String, 12 | val packageManager: String, 13 | val depName: String, 14 | val depGroup: String, 15 | val depArtifact: String, 16 | val depMetadata: String = "", 17 | val depSource: String = "", 18 | val depScope: String, 19 | val depVersion: String 20 | ) 21 | -------------------------------------------------------------------------------- /scanner_core/src/main/kotlin/org/archguard/scanner/core/sca/ScaAnalyser.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.core.sca 2 | 3 | import org.archguard.scanner.core.Analyser 4 | 5 | interface ScaAnalyser : Analyser { 6 | fun analyse(): List 7 | } 8 | -------------------------------------------------------------------------------- /scanner_core/src/main/kotlin/org/archguard/scanner/core/sca/ScaContext.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.core.sca 2 | 3 | import org.archguard.scanner.core.context.AnalyserType 4 | import org.archguard.scanner.core.context.Context 5 | 6 | interface ScaContext : Context { 7 | override val type: AnalyserType get() = AnalyserType.SCA 8 | 9 | val path: String 10 | val language: String 11 | } 12 | -------------------------------------------------------------------------------- /scanner_core/src/main/kotlin/org/archguard/scanner/core/sourcecode/ASTSourceCodeAnalyser.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.core.sourcecode 2 | 3 | import chapi.domain.core.CodeDataStruct 4 | 5 | interface ASTSourceCodeAnalyser : SourceCodeAnalyser { 6 | override fun analyse(input: Any?): Any? { 7 | return analyse(input as List) 8 | } 9 | 10 | fun analyse(input: List): Any? 11 | } 12 | -------------------------------------------------------------------------------- /scanner_core/src/main/kotlin/org/archguard/scanner/core/sourcecode/CodeDatabaseRelation.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.core.sourcecode 2 | 3 | import kotlinx.serialization.Serializable 4 | 5 | @Serializable 6 | data class CodeDatabaseRelation( 7 | val packageName: String = "", 8 | val className: String = "", 9 | val functionName: String = "", 10 | val tables: List = listOf(), 11 | val sqls: List = listOf() 12 | ) 13 | 14 | -------------------------------------------------------------------------------- /scanner_core/src/main/kotlin/org/archguard/scanner/core/sourcecode/ContainerService.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.core.sourcecode 2 | 3 | import kotlinx.serialization.Serializable 4 | 5 | @Serializable 6 | data class ContainerService( 7 | // component name, only if is a component 8 | var name: String = "", 9 | var demands: List = listOf(), 10 | var resources: List = listOf() 11 | ) 12 | 13 | @Serializable 14 | data class ContainerDemand( 15 | var source_caller: String = "", 16 | var call_routes: List = listOf(), 17 | var base: String = "", 18 | var target_url: String = "", 19 | var target_http_method: String = "", 20 | var call_data: String = "" 21 | ) 22 | 23 | @Serializable 24 | data class ContainerResource( 25 | var sourceUrl: String = "", 26 | var sourceHttpMethod: String = "", 27 | var packageName: String = "", 28 | var className: String = "", 29 | var methodName: String = "" 30 | ) 31 | -------------------------------------------------------------------------------- /scanner_core/src/main/kotlin/org/archguard/scanner/core/sourcecode/LanguageSourceCodeAnalyser.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.core.sourcecode 2 | 3 | import chapi.domain.core.CodeDataStruct 4 | import java.io.File 5 | import kotlin.streams.asStream 6 | import kotlin.streams.toList 7 | 8 | // 重载函数, 实现细粒度的接口定义 9 | interface LanguageSourceCodeAnalyser : SourceCodeAnalyser { 10 | override fun analyse(input: Any?): Any? = analyse() 11 | 12 | fun analyse(): List 13 | 14 | fun getFilesByPath(path: String, predicate: (File) -> Boolean = { true }): List { 15 | return File(path).walk().asStream().parallel() 16 | .filter { it.isFile } 17 | .filter { predicate(it) } 18 | .toList() 19 | } 20 | 21 | fun File.readContent(): String { 22 | val text = readText() 23 | // fix for Window issue 24 | if (text.startsWith("\uFEFF")) { 25 | return text.substring(1); 26 | } 27 | return text 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /scanner_core/src/main/kotlin/org/archguard/scanner/core/sourcecode/SourceCodeAnalyser.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.core.sourcecode 2 | 3 | import org.archguard.scanner.core.Analyser 4 | 5 | interface SourceCodeAnalyser : Analyser { 6 | fun analyse(input: Any?): Any? 7 | } 8 | -------------------------------------------------------------------------------- /scanner_core/src/main/kotlin/org/archguard/scanner/core/sourcecode/SourceCodeContext.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.core.sourcecode 2 | 3 | import org.archguard.scanner.core.context.AnalyserType 4 | import org.archguard.scanner.core.context.Context 5 | 6 | interface SourceCodeContext : Context { 7 | override val type: AnalyserType get() = AnalyserType.SOURCE_CODE 8 | 9 | // TODO replace with DAG 10 | val language: String 11 | val features: List 12 | val path: String 13 | } 14 | -------------------------------------------------------------------------------- /scanner_core/src/main/kotlin/org/archguard/scanner/core/utils/CoroutinesExtension.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.scanner.core.utils 2 | 3 | import kotlinx.coroutines.async 4 | import kotlinx.coroutines.awaitAll 5 | import kotlinx.coroutines.coroutineScope 6 | 7 | object CoroutinesExtension { 8 | suspend fun List.asyncMap(transform: (T) -> R) = 9 | coroutineScope { map { async { transform(it) } }.awaitAll() } 10 | } 11 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * This file was generated by the Gradle 'init' task. 3 | * 4 | * This project uses @Incubating APIs which are subject to change. 5 | */ 6 | 7 | rootProject.name = "ArchGuard Scanner" 8 | 9 | /** 10 | * scanner projects: 11 | * scanner projects: 12 | * - core: define the core models and apis 13 | * - cli: executable command line tools to manage and choregraph 14 | */ 15 | include( 16 | ":scanner_core", 17 | ":scanner_cli", 18 | // source code 19 | ":analyser_sourcecode:lang_kotlin", 20 | ":analyser_sourcecode:lang_java", 21 | ":analyser_sourcecode:lang_typescript", 22 | ":analyser_sourcecode:lang_python", 23 | ":analyser_sourcecode:lang_golang", 24 | ":analyser_sourcecode:lang_csharp", 25 | ":analyser_sourcecode:lang_scala", 26 | ":analyser_sourcecode:feat_apicalls", 27 | ":analyser_sourcecode:feat_datamap", 28 | ":analyser_git", 29 | ":analyser_diff_changes", 30 | ":analyser_sca", 31 | ":analyser_architecture", 32 | ) 33 | 34 | /** 35 | * linters projects: a specific set of analysers to detect specific patterns 36 | */ 37 | include(":rule-core") 38 | include(":rule-linter:rule-sql") 39 | include(":rule-linter:rule-test-code") 40 | include(":rule-linter:rule-webapi") 41 | include(":rule-linter:rule-code") 42 | include(":rule-doc-generator") 43 | --------------------------------------------------------------------------------